廓形仪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.

238 lines
6.9 KiB

  1. 'use client';
  2. import React from 'react';
  3. import { createCheckbox } from '@gluestack-ui/checkbox';
  4. import { View, Pressable, Text, Platform } from 'react-native';
  5. import type { TextProps, ViewProps } from 'react-native';
  6. import { tva } from '@gluestack-ui/nativewind-utils/tva';
  7. import { PrimitiveIcon, IPrimitiveIcon, UIIcon } from '@gluestack-ui/icon';
  8. import {
  9. withStyleContext,
  10. useStyleContext,
  11. } from '@gluestack-ui/nativewind-utils/withStyleContext';
  12. import { cssInterop } from 'nativewind';
  13. import type { VariantProps } from '@gluestack-ui/nativewind-utils';
  14. const IndicatorWrapper = React.forwardRef<
  15. React.ComponentRef<typeof View>,
  16. ViewProps
  17. >(function IndicatorWrapper({ ...props }, ref) {
  18. return <View {...props} ref={ref} />;
  19. });
  20. const LabelWrapper = React.forwardRef<
  21. React.ComponentRef<typeof Text>,
  22. TextProps
  23. >(function LabelWrapper({ ...props }, ref) {
  24. return <Text {...props} ref={ref} />;
  25. });
  26. const IconWrapper = React.forwardRef<
  27. React.ComponentRef<typeof PrimitiveIcon>,
  28. IPrimitiveIcon
  29. >(function IconWrapper({ ...props }, ref) {
  30. return <UIIcon {...props} ref={ref} />;
  31. });
  32. const SCOPE = 'CHECKBOX';
  33. const UICheckbox = createCheckbox({
  34. // @ts-expect-error : internal implementation for r-19/react-native-web
  35. Root:
  36. Platform.OS === 'web'
  37. ? withStyleContext(View, SCOPE)
  38. : withStyleContext(Pressable, SCOPE),
  39. Group: View,
  40. Icon: IconWrapper,
  41. Label: LabelWrapper,
  42. Indicator: IndicatorWrapper,
  43. });
  44. cssInterop(PrimitiveIcon, {
  45. className: {
  46. target: 'style',
  47. nativeStyleToProp: {
  48. height: true,
  49. width: true,
  50. fill: true,
  51. color: 'classNameColor',
  52. stroke: true,
  53. },
  54. },
  55. });
  56. const checkboxStyle = tva({
  57. base: 'group/checkbox flex-row items-center justify-start web:cursor-pointer data-[disabled=true]:cursor-not-allowed',
  58. variants: {
  59. size: {
  60. lg: 'gap-2',
  61. md: 'gap-2',
  62. sm: 'gap-1.5',
  63. },
  64. },
  65. });
  66. const checkboxIndicatorStyle = tva({
  67. base: 'justify-center items-center border-outline-400 bg-transparent rounded web:data-[focus-visible=true]:outline-none web:data-[focus-visible=true]:ring-2 web:data-[focus-visible=true]:ring-indicator-primary data-[checked=true]:bg-primary-600 data-[checked=true]:border-primary-600 data-[hover=true]:data-[checked=false]:border-outline-500 data-[hover=true]:bg-transparent data-[hover=true]:data-[invalid=true]:border-error-700 data-[hover=true]:data-[checked=true]:bg-primary-700 data-[hover=true]:data-[checked=true]:border-primary-700 data-[hover=true]:data-[checked=true]:data-[disabled=true]:border-primary-600 data-[hover=true]:data-[checked=true]:data-[disabled=true]:bg-primary-600 data-[hover=true]:data-[checked=true]:data-[disabled=true]:opacity-40 data-[hover=true]:data-[checked=true]:data-[disabled=true]:data-[invalid=true]:border-error-700 data-[hover=true]:data-[disabled=true]:border-outline-400 data-[hover=true]:data-[disabled=true]:data-[invalid=true]:border-error-700 data-[active=true]:data-[checked=true]:bg-primary-800 data-[active=true]:data-[checked=true]:border-primary-800 data-[invalid=true]:border-error-700 data-[disabled=true]:opacity-40',
  68. parentVariants: {
  69. size: {
  70. lg: 'w-6 h-6 border-[3px]',
  71. md: 'w-5 h-5 border-2',
  72. sm: 'w-4 h-4 border-2',
  73. },
  74. },
  75. });
  76. const checkboxLabelStyle = tva({
  77. base: 'text-typography-600 data-[checked=true]:text-typography-900 data-[hover=true]:text-typography-900 data-[hover=true]:data-[checked=true]:text-typography-900 data-[hover=true]:data-[checked=true]:data-[disabled=true]:text-typography-900 data-[hover=true]:data-[disabled=true]:text-typography-400 data-[active=true]:text-typography-900 data-[active=true]:data-[checked=true]:text-typography-900 data-[disabled=true]:opacity-40 web:select-none',
  78. parentVariants: {
  79. size: {
  80. lg: 'text-lg',
  81. md: 'text-base',
  82. sm: 'text-sm',
  83. },
  84. },
  85. });
  86. const checkboxIconStyle = tva({
  87. base: 'text-typography-50 fill-none',
  88. parentVariants: {
  89. size: {
  90. sm: 'h-3 w-3',
  91. md: 'h-4 w-4',
  92. lg: 'h-5 w-5',
  93. },
  94. },
  95. });
  96. const CheckboxGroup = UICheckbox.Group;
  97. type ICheckboxProps = React.ComponentPropsWithoutRef<typeof UICheckbox> &
  98. VariantProps<typeof checkboxStyle>;
  99. const Checkbox = React.forwardRef<
  100. React.ComponentRef<typeof UICheckbox>,
  101. ICheckboxProps
  102. >(function Checkbox({ className, size = 'md', ...props }, ref) {
  103. return (
  104. <UICheckbox
  105. className={checkboxStyle({
  106. class: className,
  107. size,
  108. })}
  109. {...props}
  110. context={{
  111. size,
  112. }}
  113. ref={ref}
  114. />
  115. );
  116. });
  117. type ICheckboxIndicatorProps = React.ComponentPropsWithoutRef<
  118. typeof UICheckbox.Indicator
  119. > &
  120. VariantProps<typeof checkboxIndicatorStyle>;
  121. const CheckboxIndicator = React.forwardRef<
  122. React.ComponentRef<typeof UICheckbox.Indicator>,
  123. ICheckboxIndicatorProps
  124. >(function CheckboxIndicator({ className, ...props }, ref) {
  125. const { size: parentSize } = useStyleContext(SCOPE);
  126. return (
  127. <UICheckbox.Indicator
  128. className={checkboxIndicatorStyle({
  129. parentVariants: {
  130. size: parentSize,
  131. },
  132. class: className,
  133. })}
  134. {...props}
  135. ref={ref}
  136. />
  137. );
  138. });
  139. type ICheckboxLabelProps = React.ComponentPropsWithoutRef<
  140. typeof UICheckbox.Label
  141. > &
  142. VariantProps<typeof checkboxLabelStyle>;
  143. const CheckboxLabel = React.forwardRef<
  144. React.ComponentRef<typeof UICheckbox.Label>,
  145. ICheckboxLabelProps
  146. >(function CheckboxLabel({ className, ...props }, ref) {
  147. const { size: parentSize } = useStyleContext(SCOPE);
  148. return (
  149. <UICheckbox.Label
  150. className={checkboxLabelStyle({
  151. parentVariants: {
  152. size: parentSize,
  153. },
  154. class: className,
  155. })}
  156. {...props}
  157. ref={ref}
  158. />
  159. );
  160. });
  161. type ICheckboxIconProps = React.ComponentPropsWithoutRef<
  162. typeof UICheckbox.Icon
  163. > &
  164. VariantProps<typeof checkboxIconStyle>;
  165. const CheckboxIcon = React.forwardRef<
  166. React.ComponentRef<typeof UICheckbox.Icon>,
  167. ICheckboxIconProps
  168. >(function CheckboxIcon({ className, size, ...props }, ref) {
  169. const { size: parentSize } = useStyleContext(SCOPE);
  170. if (typeof size === 'number') {
  171. return (
  172. <UICheckbox.Icon
  173. ref={ref}
  174. {...props}
  175. className={checkboxIconStyle({ class: className })}
  176. size={size}
  177. />
  178. );
  179. } else if (
  180. (props.height !== undefined || props.width !== undefined) &&
  181. size === undefined
  182. ) {
  183. return (
  184. <UICheckbox.Icon
  185. ref={ref}
  186. {...props}
  187. className={checkboxIconStyle({ class: className })}
  188. />
  189. );
  190. }
  191. return (
  192. <UICheckbox.Icon
  193. className={checkboxIconStyle({
  194. parentVariants: {
  195. size: parentSize,
  196. },
  197. class: className,
  198. size,
  199. })}
  200. {...props}
  201. ref={ref}
  202. />
  203. );
  204. });
  205. Checkbox.displayName = 'Checkbox';
  206. CheckboxIndicator.displayName = 'CheckboxIndicator';
  207. CheckboxLabel.displayName = 'CheckboxLabel';
  208. CheckboxIcon.displayName = 'CheckboxIcon';
  209. export {
  210. Checkbox,
  211. CheckboxIndicator,
  212. CheckboxLabel,
  213. CheckboxIcon,
  214. CheckboxGroup,
  215. };