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

240 lines
5.4 KiB

  1. 'use client';
  2. import React from 'react';
  3. import { createToastHook } from '@gluestack-ui/toast';
  4. import { AccessibilityInfo, Text, View, ViewStyle } from 'react-native';
  5. import { tva } from '@gluestack-ui/nativewind-utils/tva';
  6. import { cssInterop } from 'nativewind';
  7. import {
  8. Motion,
  9. AnimatePresence,
  10. MotionComponentProps,
  11. } from '@legendapp/motion';
  12. import {
  13. withStyleContext,
  14. useStyleContext,
  15. } from '@gluestack-ui/nativewind-utils/withStyleContext';
  16. import type { VariantProps } from '@gluestack-ui/nativewind-utils';
  17. type IMotionViewProps = React.ComponentProps<typeof View> &
  18. MotionComponentProps<typeof View, ViewStyle, unknown, unknown, unknown>;
  19. const MotionView = Motion.View as React.ComponentType<IMotionViewProps>;
  20. const useToast = createToastHook(MotionView, AnimatePresence);
  21. const SCOPE = 'TOAST';
  22. cssInterop(MotionView, { className: 'style' });
  23. const toastStyle = tva({
  24. base: 'p-4 m-1 rounded-md gap-1 web:pointer-events-auto shadow-hard-5 border-outline-100',
  25. variants: {
  26. action: {
  27. error: 'bg-error-800',
  28. warning: 'bg-warning-700',
  29. success: 'bg-success-700',
  30. info: 'bg-info-700',
  31. muted: 'bg-background-800',
  32. },
  33. variant: {
  34. solid: '',
  35. outline: 'border bg-background-0',
  36. },
  37. },
  38. });
  39. const toastTitleStyle = tva({
  40. base: 'text-typography-0 font-medium font-body tracking-md text-left',
  41. variants: {
  42. isTruncated: {
  43. true: '',
  44. },
  45. bold: {
  46. true: 'font-bold',
  47. },
  48. underline: {
  49. true: 'underline',
  50. },
  51. strikeThrough: {
  52. true: 'line-through',
  53. },
  54. size: {
  55. '2xs': 'text-2xs',
  56. 'xs': 'text-xs',
  57. 'sm': 'text-sm',
  58. 'md': 'text-base',
  59. 'lg': 'text-lg',
  60. 'xl': 'text-xl',
  61. '2xl': 'text-2xl',
  62. '3xl': 'text-3xl',
  63. '4xl': 'text-4xl',
  64. '5xl': 'text-5xl',
  65. '6xl': 'text-6xl',
  66. },
  67. },
  68. parentVariants: {
  69. variant: {
  70. solid: '',
  71. outline: '',
  72. },
  73. action: {
  74. error: '',
  75. warning: '',
  76. success: '',
  77. info: '',
  78. muted: '',
  79. },
  80. },
  81. parentCompoundVariants: [
  82. {
  83. variant: 'outline',
  84. action: 'error',
  85. class: 'text-error-800',
  86. },
  87. {
  88. variant: 'outline',
  89. action: 'warning',
  90. class: 'text-warning-800',
  91. },
  92. {
  93. variant: 'outline',
  94. action: 'success',
  95. class: 'text-success-800',
  96. },
  97. {
  98. variant: 'outline',
  99. action: 'info',
  100. class: 'text-info-800',
  101. },
  102. {
  103. variant: 'outline',
  104. action: 'muted',
  105. class: 'text-background-800',
  106. },
  107. ],
  108. });
  109. const toastDescriptionStyle = tva({
  110. base: 'font-normal font-body tracking-md text-left',
  111. variants: {
  112. isTruncated: {
  113. true: '',
  114. },
  115. bold: {
  116. true: 'font-bold',
  117. },
  118. underline: {
  119. true: 'underline',
  120. },
  121. strikeThrough: {
  122. true: 'line-through',
  123. },
  124. size: {
  125. '2xs': 'text-2xs',
  126. 'xs': 'text-xs',
  127. 'sm': 'text-sm',
  128. 'md': 'text-base',
  129. 'lg': 'text-lg',
  130. 'xl': 'text-xl',
  131. '2xl': 'text-2xl',
  132. '3xl': 'text-3xl',
  133. '4xl': 'text-4xl',
  134. '5xl': 'text-5xl',
  135. '6xl': 'text-6xl',
  136. },
  137. },
  138. parentVariants: {
  139. variant: {
  140. solid: 'text-typography-50',
  141. outline: 'text-typography-900',
  142. },
  143. },
  144. });
  145. const Root = withStyleContext(View, SCOPE);
  146. type IToastProps = React.ComponentProps<typeof Root> & {
  147. className?: string;
  148. } & VariantProps<typeof toastStyle>;
  149. const Toast = React.forwardRef<React.ComponentRef<typeof Root>, IToastProps>(
  150. function Toast(
  151. { className, variant = 'solid', action = 'muted', ...props },
  152. ref
  153. ) {
  154. return (
  155. <Root
  156. ref={ref}
  157. className={toastStyle({ variant, action, class: className })}
  158. context={{ variant, action }}
  159. {...props}
  160. />
  161. );
  162. }
  163. );
  164. type IToastTitleProps = React.ComponentProps<typeof Text> & {
  165. className?: string;
  166. } & VariantProps<typeof toastTitleStyle>;
  167. const ToastTitle = React.forwardRef<
  168. React.ComponentRef<typeof Text>,
  169. IToastTitleProps
  170. >(function ToastTitle({ className, size = 'md', children, ...props }, ref) {
  171. const { variant: parentVariant, action: parentAction } =
  172. useStyleContext(SCOPE);
  173. React.useEffect(() => {
  174. // Issue from react-native side
  175. // Hack for now, will fix this later
  176. AccessibilityInfo.announceForAccessibility(children as string);
  177. }, [children]);
  178. return (
  179. <Text
  180. {...props}
  181. ref={ref}
  182. aria-live="assertive"
  183. aria-atomic="true"
  184. role="alert"
  185. className={toastTitleStyle({
  186. size,
  187. class: className,
  188. parentVariants: {
  189. variant: parentVariant,
  190. action: parentAction,
  191. },
  192. })}
  193. >
  194. {children}
  195. </Text>
  196. );
  197. });
  198. type IToastDescriptionProps = React.ComponentProps<typeof Text> & {
  199. className?: string;
  200. } & VariantProps<typeof toastDescriptionStyle>;
  201. const ToastDescription = React.forwardRef<
  202. React.ComponentRef<typeof Text>,
  203. IToastDescriptionProps
  204. >(function ToastDescription({ className, size = 'md', ...props }, ref) {
  205. const { variant: parentVariant } = useStyleContext(SCOPE);
  206. return (
  207. <Text
  208. ref={ref}
  209. {...props}
  210. className={toastDescriptionStyle({
  211. size,
  212. class: className,
  213. parentVariants: {
  214. variant: parentVariant,
  215. },
  216. })}
  217. />
  218. );
  219. });
  220. Toast.displayName = 'Toast';
  221. ToastTitle.displayName = 'ToastTitle';
  222. ToastDescription.displayName = 'ToastDescription';
  223. export { useToast, Toast, ToastTitle, ToastDescription };