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

245 lines
5.0 KiB

  1. 'use client';
  2. import { createAlert } from '@gluestack-ui/alert';
  3. import { View, Text } from 'react-native';
  4. import { tva } from '@gluestack-ui/nativewind-utils/tva';
  5. import {
  6. withStyleContext,
  7. useStyleContext,
  8. } from '@gluestack-ui/nativewind-utils/withStyleContext';
  9. import React from 'react';
  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 = 'ALERT';
  14. const alertStyle = tva({
  15. base: 'items-center py-3 px-4 rounded-md flex-row gap-2 border-outline-100',
  16. variants: {
  17. action: {
  18. error: 'bg-background-error',
  19. warning: 'bg-background-warning',
  20. success: 'bg-background-success',
  21. info: 'bg-background-info',
  22. muted: 'bg-background-muted',
  23. },
  24. variant: {
  25. solid: '',
  26. outline: 'border bg-background-0',
  27. },
  28. },
  29. });
  30. const alertTextStyle = tva({
  31. base: 'font-normal font-body',
  32. variants: {
  33. isTruncated: {
  34. true: 'web:truncate',
  35. },
  36. bold: {
  37. true: 'font-bold',
  38. },
  39. underline: {
  40. true: 'underline',
  41. },
  42. strikeThrough: {
  43. true: 'line-through',
  44. },
  45. size: {
  46. '2xs': 'text-2xs',
  47. 'xs': 'text-xs',
  48. 'sm': 'text-sm',
  49. 'md': 'text-base',
  50. 'lg': 'text-lg',
  51. 'xl': 'text-xl',
  52. '2xl': 'text-2xl',
  53. '3xl': 'text-3xl',
  54. '4xl': 'text-4xl',
  55. '5xl': 'text-5xl',
  56. '6xl': 'text-6xl',
  57. },
  58. sub: {
  59. true: 'text-xs',
  60. },
  61. italic: {
  62. true: 'italic',
  63. },
  64. highlight: {
  65. true: 'bg-yellow-500',
  66. },
  67. },
  68. parentVariants: {
  69. action: {
  70. error: 'text-error-800',
  71. warning: 'text-warning-800',
  72. success: 'text-success-800',
  73. info: 'text-info-800',
  74. muted: 'text-background-800',
  75. },
  76. },
  77. });
  78. const alertIconStyle = tva({
  79. base: 'fill-none',
  80. variants: {
  81. size: {
  82. '2xs': 'h-3 w-3',
  83. 'xs': 'h-3.5 w-3.5',
  84. 'sm': 'h-4 w-4',
  85. 'md': 'h-[18px] w-[18px]',
  86. 'lg': 'h-5 w-5',
  87. 'xl': 'h-6 w-6',
  88. },
  89. },
  90. parentVariants: {
  91. action: {
  92. error: 'text-error-800',
  93. warning: 'text-warning-800',
  94. success: 'text-success-800',
  95. info: 'text-info-800',
  96. muted: 'text-background-800',
  97. },
  98. },
  99. });
  100. export const UIAlert = createAlert({
  101. Root: withStyleContext(View, SCOPE),
  102. Text: Text,
  103. Icon: UIIcon,
  104. });
  105. cssInterop(PrimitiveIcon, {
  106. className: {
  107. target: 'style',
  108. nativeStyleToProp: {
  109. height: true,
  110. width: true,
  111. fill: true,
  112. color: 'classNameColor',
  113. stroke: true,
  114. },
  115. },
  116. });
  117. type IAlertProps = Omit<
  118. React.ComponentPropsWithoutRef<typeof UIAlert>,
  119. 'context'
  120. > &
  121. VariantProps<typeof alertStyle>;
  122. const Alert = React.forwardRef<React.ComponentRef<typeof UIAlert>, IAlertProps>(
  123. function Alert(
  124. { className, variant = 'solid', action = 'muted', ...props },
  125. ref
  126. ) {
  127. return (
  128. <UIAlert
  129. className={alertStyle({ action, variant, class: className })}
  130. context={{ variant, action }}
  131. ref={ref}
  132. {...props}
  133. />
  134. );
  135. }
  136. );
  137. type IAlertTextProps = React.ComponentPropsWithoutRef<typeof UIAlert.Text> &
  138. VariantProps<typeof alertTextStyle>;
  139. const AlertText = React.forwardRef<
  140. React.ComponentRef<typeof UIAlert.Text>,
  141. IAlertTextProps
  142. >(function AlertText(
  143. {
  144. className,
  145. isTruncated,
  146. bold,
  147. underline,
  148. strikeThrough,
  149. size = 'md',
  150. sub,
  151. italic,
  152. highlight,
  153. ...props
  154. },
  155. ref
  156. ) {
  157. const { action: parentAction } = useStyleContext(SCOPE);
  158. return (
  159. <UIAlert.Text
  160. className={alertTextStyle({
  161. isTruncated,
  162. bold,
  163. underline,
  164. strikeThrough,
  165. size,
  166. sub,
  167. italic,
  168. highlight,
  169. class: className,
  170. parentVariants: {
  171. action: parentAction,
  172. },
  173. })}
  174. {...props}
  175. ref={ref}
  176. />
  177. );
  178. });
  179. type IAlertIconProps = React.ComponentPropsWithoutRef<typeof UIAlert.Icon> &
  180. VariantProps<typeof alertIconStyle> & {
  181. height?: number;
  182. width?: number;
  183. };
  184. const AlertIcon = React.forwardRef<
  185. React.ComponentRef<typeof UIAlert.Icon>,
  186. IAlertIconProps
  187. >(function AlertIcon({ className, size = 'md', ...props }, ref) {
  188. const { action: parentAction } = useStyleContext(SCOPE);
  189. if (typeof size === 'number') {
  190. return (
  191. <UIAlert.Icon
  192. ref={ref}
  193. {...props}
  194. className={alertIconStyle({ class: className })}
  195. size={size}
  196. />
  197. );
  198. } else if (
  199. (props.height !== undefined || props.width !== undefined) &&
  200. size === undefined
  201. ) {
  202. return (
  203. <UIAlert.Icon
  204. ref={ref}
  205. {...props}
  206. className={alertIconStyle({ class: className })}
  207. />
  208. );
  209. }
  210. return (
  211. <UIAlert.Icon
  212. className={alertIconStyle({
  213. parentVariants: {
  214. action: parentAction,
  215. },
  216. size,
  217. class: className,
  218. })}
  219. {...props}
  220. ref={ref}
  221. />
  222. );
  223. });
  224. Alert.displayName = 'Alert';
  225. AlertText.displayName = 'AlertText';
  226. AlertIcon.displayName = 'AlertIcon';
  227. export { Alert, AlertText, AlertIcon };