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

217 lines
7.2 KiB

  1. 'use client';
  2. import React from 'react';
  3. import { createInput } from '@gluestack-ui/input';
  4. import { View, Pressable, TextInput } 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 = 'INPUT';
  14. const UIInput = createInput({
  15. Root: withStyleContext(View, SCOPE),
  16. Icon: UIIcon,
  17. Slot: Pressable,
  18. Input: TextInput,
  19. });
  20. cssInterop(PrimitiveIcon, {
  21. className: {
  22. target: 'style',
  23. nativeStyleToProp: {
  24. height: true,
  25. width: true,
  26. fill: true,
  27. color: 'classNameColor',
  28. stroke: true,
  29. },
  30. },
  31. });
  32. const inputStyle = tva({
  33. base: 'border-background-300 flex-row overflow-hidden content-center data-[hover=true]:border-outline-400 data-[focus=true]:border-primary-700 data-[focus=true]:hover:border-primary-700 data-[disabled=true]:opacity-40 data-[disabled=true]:hover:border-background-300 items-center',
  34. variants: {
  35. size: {
  36. xl: 'h-12',
  37. lg: 'h-11',
  38. md: 'h-10',
  39. sm: 'h-9',
  40. },
  41. variant: {
  42. underlined:
  43. 'rounded-none border-b data-[invalid=true]:border-b-2 data-[invalid=true]:border-error-700 data-[invalid=true]:hover:border-error-700 data-[invalid=true]:data-[focus=true]:border-error-700 data-[invalid=true]:data-[focus=true]:hover:border-error-700 data-[invalid=true]:data-[disabled=true]:hover:border-error-700',
  44. outline:
  45. 'rounded border data-[invalid=true]:border-error-700 data-[invalid=true]:hover:border-error-700 data-[invalid=true]:data-[focus=true]:border-error-700 data-[invalid=true]:data-[focus=true]:hover:border-error-700 data-[invalid=true]:data-[disabled=true]:hover:border-error-700 data-[focus=true]:web:ring-1 data-[focus=true]:web:ring-inset data-[focus=true]:web:ring-indicator-primary data-[invalid=true]:web:ring-1 data-[invalid=true]:web:ring-inset data-[invalid=true]:web:ring-indicator-error data-[invalid=true]:data-[focus=true]:hover:web:ring-1 data-[invalid=true]:data-[focus=true]:hover:web:ring-inset data-[invalid=true]:data-[focus=true]:hover:web:ring-indicator-error data-[invalid=true]:data-[disabled=true]:hover:web:ring-1 data-[invalid=true]:data-[disabled=true]:hover:web:ring-inset data-[invalid=true]:data-[disabled=true]:hover:web:ring-indicator-error',
  46. rounded:
  47. 'rounded-full border data-[invalid=true]:border-error-700 data-[invalid=true]:hover:border-error-700 data-[invalid=true]:data-[focus=true]:border-error-700 data-[invalid=true]:data-[focus=true]:hover:border-error-700 data-[invalid=true]:data-[disabled=true]:hover:border-error-700 data-[focus=true]:web:ring-1 data-[focus=true]:web:ring-inset data-[focus=true]:web:ring-indicator-primary data-[invalid=true]:web:ring-1 data-[invalid=true]:web:ring-inset data-[invalid=true]:web:ring-indicator-error data-[invalid=true]:data-[focus=true]:hover:web:ring-1 data-[invalid=true]:data-[focus=true]:hover:web:ring-inset data-[invalid=true]:data-[focus=true]:hover:web:ring-indicator-error data-[invalid=true]:data-[disabled=true]:hover:web:ring-1 data-[invalid=true]:data-[disabled=true]:hover:web:ring-inset data-[invalid=true]:data-[disabled=true]:hover:web:ring-indicator-error',
  48. },
  49. },
  50. });
  51. const inputIconStyle = tva({
  52. base: 'justify-center items-center text-typography-400 fill-none',
  53. parentVariants: {
  54. size: {
  55. '2xs': 'h-3 w-3',
  56. 'xs': 'h-3.5 w-3.5',
  57. 'sm': 'h-4 w-4',
  58. 'md': 'h-[18px] w-[18px]',
  59. 'lg': 'h-5 w-5',
  60. 'xl': 'h-6 w-6',
  61. },
  62. },
  63. });
  64. const inputSlotStyle = tva({
  65. base: 'justify-center items-center web:disabled:cursor-not-allowed',
  66. });
  67. const inputFieldStyle = tva({
  68. base: 'flex-1 text-typography-900 py-0 px-3 placeholder:text-typography-500 h-full ios:leading-[0px] web:cursor-text web:data-[disabled=true]:cursor-not-allowed',
  69. parentVariants: {
  70. variant: {
  71. underlined: 'web:outline-0 web:outline-none px-0',
  72. outline: 'web:outline-0 web:outline-none',
  73. rounded: 'web:outline-0 web:outline-none px-4',
  74. },
  75. size: {
  76. '2xs': 'text-2xs',
  77. 'xs': 'text-xs',
  78. 'sm': 'text-sm',
  79. 'md': 'text-base',
  80. 'lg': 'text-lg',
  81. 'xl': 'text-xl',
  82. '2xl': 'text-2xl',
  83. '3xl': 'text-3xl',
  84. '4xl': 'text-4xl',
  85. '5xl': 'text-5xl',
  86. '6xl': 'text-6xl',
  87. },
  88. },
  89. });
  90. type IInputProps = React.ComponentProps<typeof UIInput> &
  91. VariantProps<typeof inputStyle> & { className?: string };
  92. const Input = React.forwardRef<React.ComponentRef<typeof UIInput>, IInputProps>(
  93. function Input(
  94. { className, variant = 'outline', size = 'md', ...props },
  95. ref
  96. ) {
  97. return (
  98. <UIInput
  99. ref={ref}
  100. {...props}
  101. className={inputStyle({ variant, size, class: className })}
  102. context={{ variant, size }}
  103. />
  104. );
  105. }
  106. );
  107. type IInputIconProps = React.ComponentProps<typeof UIInput.Icon> &
  108. VariantProps<typeof inputIconStyle> & {
  109. className?: string;
  110. height?: number;
  111. width?: number;
  112. };
  113. const InputIcon = React.forwardRef<
  114. React.ComponentRef<typeof UIInput.Icon>,
  115. IInputIconProps
  116. >(function InputIcon({ className, size, ...props }, ref) {
  117. const { size: parentSize } = useStyleContext(SCOPE);
  118. if (typeof size === 'number') {
  119. return (
  120. <UIInput.Icon
  121. ref={ref}
  122. {...props}
  123. className={inputIconStyle({ class: className })}
  124. size={size}
  125. />
  126. );
  127. } else if (
  128. (props.height !== undefined || props.width !== undefined) &&
  129. size === undefined
  130. ) {
  131. return (
  132. <UIInput.Icon
  133. ref={ref}
  134. {...props}
  135. className={inputIconStyle({ class: className })}
  136. />
  137. );
  138. }
  139. return (
  140. <UIInput.Icon
  141. ref={ref}
  142. {...props}
  143. className={inputIconStyle({
  144. parentVariants: {
  145. size: parentSize,
  146. },
  147. class: className,
  148. })}
  149. />
  150. );
  151. });
  152. type IInputSlotProps = React.ComponentProps<typeof UIInput.Slot> &
  153. VariantProps<typeof inputSlotStyle> & { className?: string };
  154. const InputSlot = React.forwardRef<
  155. React.ComponentRef<typeof UIInput.Slot>,
  156. IInputSlotProps
  157. >(function InputSlot({ className, ...props }, ref) {
  158. return (
  159. <UIInput.Slot
  160. ref={ref}
  161. {...props}
  162. className={inputSlotStyle({
  163. class: className,
  164. })}
  165. />
  166. );
  167. });
  168. type IInputFieldProps = React.ComponentProps<typeof UIInput.Input> &
  169. VariantProps<typeof inputFieldStyle> & { className?: string };
  170. const InputField = React.forwardRef<
  171. React.ComponentRef<typeof UIInput.Input>,
  172. IInputFieldProps
  173. >(function InputField({ className, ...props }, ref) {
  174. const { variant: parentVariant, size: parentSize } = useStyleContext(SCOPE);
  175. return (
  176. <UIInput.Input
  177. ref={ref}
  178. {...props}
  179. className={inputFieldStyle({
  180. parentVariants: {
  181. variant: parentVariant,
  182. size: parentSize,
  183. },
  184. class: className,
  185. })}
  186. />
  187. );
  188. });
  189. Input.displayName = 'Input';
  190. InputIcon.displayName = 'InputIcon';
  191. InputSlot.displayName = 'InputSlot';
  192. InputField.displayName = 'InputField';
  193. export { Input, InputField, InputIcon, InputSlot };