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

214 lines
4.6 KiB

  1. 'use client';
  2. import React from 'react';
  3. import { Text, View } from 'react-native';
  4. import { PrimitiveIcon, UIIcon } from '@gluestack-ui/icon';
  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 { Svg } from 'react-native-svg';
  13. const SCOPE = 'BADGE';
  14. const badgeStyle = tva({
  15. base: 'flex-row items-center rounded-sm data-[disabled=true]:opacity-50 px-2 py-1',
  16. variants: {
  17. action: {
  18. error: 'bg-background-error border-error-300',
  19. warning: 'bg-background-warning border-warning-300',
  20. success: 'bg-background-success border-success-300',
  21. info: 'bg-background-info border-info-300',
  22. muted: 'bg-background-muted border-background-300',
  23. },
  24. variant: {
  25. solid: '',
  26. outline: 'border',
  27. },
  28. size: {
  29. sm: '',
  30. md: '',
  31. lg: '',
  32. },
  33. },
  34. });
  35. const badgeTextStyle = tva({
  36. base: 'text-typography-700 font-body font-normal tracking-normal uppercase',
  37. parentVariants: {
  38. action: {
  39. error: 'text-error-600',
  40. warning: 'text-warning-600',
  41. success: 'text-success-600',
  42. info: 'text-info-600',
  43. muted: 'text-background-800',
  44. },
  45. size: {
  46. sm: 'text-2xs',
  47. md: 'text-xs',
  48. lg: 'text-sm',
  49. },
  50. },
  51. variants: {
  52. isTruncated: {
  53. true: 'web:truncate',
  54. },
  55. bold: {
  56. true: 'font-bold',
  57. },
  58. underline: {
  59. true: 'underline',
  60. },
  61. strikeThrough: {
  62. true: 'line-through',
  63. },
  64. sub: {
  65. true: 'text-xs',
  66. },
  67. italic: {
  68. true: 'italic',
  69. },
  70. highlight: {
  71. true: 'bg-yellow-500',
  72. },
  73. },
  74. });
  75. const badgeIconStyle = tva({
  76. base: 'fill-none',
  77. parentVariants: {
  78. action: {
  79. error: 'text-error-600',
  80. warning: 'text-warning-600',
  81. success: 'text-success-600',
  82. info: 'text-info-600',
  83. muted: 'text-background-800',
  84. },
  85. size: {
  86. sm: 'h-3 w-3',
  87. md: 'h-3.5 w-3.5',
  88. lg: 'h-4 w-4',
  89. },
  90. },
  91. });
  92. const ContextView = withStyleContext(View, SCOPE);
  93. cssInterop(PrimitiveIcon, {
  94. className: {
  95. target: 'style',
  96. nativeStyleToProp: {
  97. height: true,
  98. width: true,
  99. fill: true,
  100. color: 'classNameColor',
  101. stroke: true,
  102. },
  103. },
  104. });
  105. type IBadgeProps = React.ComponentPropsWithoutRef<typeof ContextView> &
  106. VariantProps<typeof badgeStyle>;
  107. function Badge({
  108. children,
  109. action = 'muted',
  110. variant = 'solid',
  111. size = 'md',
  112. className,
  113. ...props
  114. }: { className?: string } & IBadgeProps) {
  115. return (
  116. <ContextView
  117. className={badgeStyle({ action, variant, class: className })}
  118. {...props}
  119. context={{
  120. action,
  121. variant,
  122. size,
  123. }}
  124. >
  125. {children}
  126. </ContextView>
  127. );
  128. }
  129. type IBadgeTextProps = React.ComponentPropsWithoutRef<typeof Text> &
  130. VariantProps<typeof badgeTextStyle>;
  131. const BadgeText = React.forwardRef<
  132. React.ComponentRef<typeof Text>,
  133. IBadgeTextProps
  134. >(function BadgeText({ children, className, size, ...props }, ref) {
  135. const { size: parentSize, action: parentAction } = useStyleContext(SCOPE);
  136. return (
  137. <Text
  138. ref={ref}
  139. className={badgeTextStyle({
  140. parentVariants: {
  141. size: parentSize,
  142. action: parentAction,
  143. },
  144. size,
  145. class: className,
  146. })}
  147. {...props}
  148. >
  149. {children}
  150. </Text>
  151. );
  152. });
  153. type IBadgeIconProps = React.ComponentPropsWithoutRef<typeof PrimitiveIcon> &
  154. VariantProps<typeof badgeIconStyle>;
  155. const BadgeIcon = React.forwardRef<
  156. React.ComponentRef<typeof Svg>,
  157. IBadgeIconProps
  158. >(function BadgeIcon({ className, size, ...props }, ref) {
  159. const { size: parentSize, action: parentAction } = useStyleContext(SCOPE);
  160. if (typeof size === 'number') {
  161. return (
  162. <UIIcon
  163. ref={ref}
  164. {...props}
  165. className={badgeIconStyle({ class: className })}
  166. size={size}
  167. />
  168. );
  169. } else if (
  170. (props?.height !== undefined || props?.width !== undefined) &&
  171. size === undefined
  172. ) {
  173. return (
  174. <UIIcon
  175. ref={ref}
  176. {...props}
  177. className={badgeIconStyle({ class: className })}
  178. />
  179. );
  180. }
  181. return (
  182. <UIIcon
  183. className={badgeIconStyle({
  184. parentVariants: {
  185. size: parentSize,
  186. action: parentAction,
  187. },
  188. size,
  189. class: className,
  190. })}
  191. {...props}
  192. ref={ref}
  193. />
  194. );
  195. });
  196. Badge.displayName = 'Badge';
  197. BadgeText.displayName = 'BadgeText';
  198. BadgeIcon.displayName = 'BadgeIcon';
  199. export { Badge, BadgeIcon, BadgeText };