廓形仪rn版本-技术调研
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

  1. 'use client';
  2. import React from 'react';
  3. import { createRadio } from '@gluestack-ui/radio';
  4. import { Pressable, View, Platform, Text } from 'react-native';
  5. import { tva } from '@gluestack-ui/nativewind-utils/tva';
  6. import {
  7. withStyleContext,
  8. useStyleContext,
  9. } from '@gluestack-ui/nativewind-utils/withStyleContext';
  10. import { cssInterop } from 'nativewind';
  11. import type { VariantProps } from '@gluestack-ui/nativewind-utils';
  12. import { PrimitiveIcon, UIIcon } from '@gluestack-ui/icon';
  13. const SCOPE = 'Radio';
  14. const UIRadio = createRadio({
  15. Root: (Platform.OS === 'web'
  16. ? withStyleContext(View, SCOPE)
  17. : withStyleContext(Pressable, SCOPE)) as ReturnType<
  18. typeof withStyleContext<typeof Pressable>
  19. >,
  20. Group: View,
  21. Icon: UIIcon,
  22. Indicator: View,
  23. Label: Text,
  24. });
  25. cssInterop(PrimitiveIcon, {
  26. className: {
  27. target: 'style',
  28. nativeStyleToProp: {
  29. height: true,
  30. width: true,
  31. fill: true,
  32. color: 'classNameColor',
  33. stroke: true,
  34. },
  35. },
  36. });
  37. const radioStyle = tva({
  38. base: 'group/radio flex-row justify-start items-center web:cursor-pointer data-[disabled=true]:web:cursor-not-allowed',
  39. variants: {
  40. size: {
  41. sm: 'gap-1.5',
  42. md: 'gap-2',
  43. lg: 'gap-2',
  44. },
  45. },
  46. });
  47. const radioGroupStyle = tva({
  48. base: 'gap-2',
  49. });
  50. const radioIconStyle = tva({
  51. base: 'rounded-full justify-center items-center text-primary-800 fill-primary-800',
  52. parentVariants: {
  53. size: {
  54. sm: 'h-[9px] w-[9px]',
  55. md: 'h-3 w-3',
  56. lg: 'h-4 w-4',
  57. },
  58. },
  59. });
  60. const radioIndicatorStyle = tva({
  61. 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',
  62. parentVariants: {
  63. size: {
  64. sm: 'h-4 w-4',
  65. md: 'h-5 w-5',
  66. lg: 'h-6 w-6',
  67. },
  68. },
  69. });
  70. const radioLabelStyle = tva({
  71. 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',
  72. parentVariants: {
  73. size: {
  74. '2xs': 'text-2xs',
  75. 'xs': 'text-xs',
  76. 'sm': 'text-sm',
  77. 'md': 'text-base',
  78. 'lg': 'text-lg',
  79. 'xl': 'text-xl',
  80. '2xl': 'text-2xl',
  81. '3xl': 'text-3xl',
  82. '4xl': 'text-4xl',
  83. '5xl': 'text-5xl',
  84. '6xl': 'text-6xl',
  85. },
  86. },
  87. });
  88. type IRadioProps = Omit<React.ComponentProps<typeof UIRadio>, 'context'> &
  89. VariantProps<typeof radioStyle>;
  90. const Radio = React.forwardRef<React.ComponentRef<typeof UIRadio>, IRadioProps>(
  91. function Radio({ className, size = 'md', ...props }, ref) {
  92. return (
  93. <UIRadio
  94. className={radioStyle({ class: className, size })}
  95. {...props}
  96. ref={ref}
  97. context={{ size }}
  98. />
  99. );
  100. }
  101. );
  102. type IRadioGroupProps = React.ComponentProps<typeof UIRadio.Group> &
  103. VariantProps<typeof radioGroupStyle>;
  104. const RadioGroup = React.forwardRef<
  105. React.ComponentRef<typeof UIRadio.Group>,
  106. IRadioGroupProps
  107. >(function RadioGroup({ className, ...props }, ref) {
  108. return (
  109. <UIRadio.Group
  110. className={radioGroupStyle({ class: className })}
  111. {...props}
  112. ref={ref}
  113. />
  114. );
  115. });
  116. type IRadioIndicatorProps = React.ComponentProps<typeof UIRadio.Indicator> &
  117. VariantProps<typeof radioIndicatorStyle>;
  118. const RadioIndicator = React.forwardRef<
  119. React.ComponentRef<typeof UIRadio.Indicator>,
  120. IRadioIndicatorProps
  121. >(function RadioIndicator({ className, ...props }, ref) {
  122. const { size } = useStyleContext(SCOPE);
  123. return (
  124. <UIRadio.Indicator
  125. className={radioIndicatorStyle({
  126. parentVariants: { size },
  127. class: className,
  128. })}
  129. ref={ref}
  130. {...props}
  131. />
  132. );
  133. });
  134. type IRadioLabelProps = React.ComponentProps<typeof UIRadio.Label> &
  135. VariantProps<typeof radioIndicatorStyle>;
  136. const RadioLabel = React.forwardRef<
  137. React.ComponentRef<typeof UIRadio.Label>,
  138. IRadioLabelProps
  139. >(function RadioLabel({ className, ...props }, ref) {
  140. const { size } = useStyleContext(SCOPE);
  141. return (
  142. <UIRadio.Label
  143. className={radioLabelStyle({
  144. parentVariants: { size },
  145. class: className,
  146. })}
  147. ref={ref}
  148. {...props}
  149. />
  150. );
  151. });
  152. type IRadioIconProps = React.ComponentProps<typeof UIRadio.Icon> &
  153. VariantProps<typeof radioIconStyle> & {
  154. height?: number;
  155. width?: number;
  156. };
  157. const RadioIcon = React.forwardRef<
  158. React.ComponentRef<typeof UIRadio.Icon>,
  159. IRadioIconProps
  160. >(function RadioIcon({ className, size, ...props }, ref) {
  161. const { size: parentSize } = useStyleContext(SCOPE);
  162. if (typeof size === 'number') {
  163. return (
  164. <UIRadio.Icon
  165. ref={ref}
  166. {...props}
  167. className={radioIconStyle({ class: className })}
  168. size={size}
  169. />
  170. );
  171. } else if (
  172. (props.height !== undefined || props.width !== undefined) &&
  173. size === undefined
  174. ) {
  175. return (
  176. <UIRadio.Icon
  177. ref={ref}
  178. {...props}
  179. className={radioIconStyle({ class: className })}
  180. />
  181. );
  182. }
  183. return (
  184. <UIRadio.Icon
  185. {...props}
  186. className={radioIconStyle({
  187. parentVariants: {
  188. size: parentSize,
  189. },
  190. size,
  191. class: className,
  192. })}
  193. ref={ref}
  194. />
  195. );
  196. });
  197. Radio.displayName = 'Radio';
  198. RadioGroup.displayName = 'RadioGroup';
  199. RadioIndicator.displayName = 'RadioIndicator';
  200. RadioLabel.displayName = 'RadioLabel';
  201. RadioIcon.displayName = 'RadioIcon';
  202. export { Radio, RadioGroup, RadioIndicator, RadioLabel, RadioIcon };