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

224 lines
5.0 KiB

  1. 'use client';
  2. import React from 'react';
  3. import { createFab } from '@gluestack-ui/fab';
  4. import { Pressable, Text } 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 = 'FAB';
  14. const Root = withStyleContext(Pressable, SCOPE);
  15. const UIFab = createFab({
  16. Root: Root,
  17. Label: Text,
  18. Icon: UIIcon,
  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 fabStyle = tva({
  33. base: 'group/fab bg-primary-500 rounded-full z-20 p-4 flex-row items-center justify-center absolute hover:bg-primary-600 active:bg-primary-700 disabled:opacity-40 disabled:pointer-events-all disabled:cursor-not-allowed data-[focus=true]:web:outline-none data-[focus-visible=true]:web:ring-2 data-[focus-visible=true]:web:ring-indicator-info shadow-hard-2',
  34. variants: {
  35. size: {
  36. sm: 'px-2.5 py-2.5',
  37. md: 'px-3 py-3',
  38. lg: 'px-4 py-4',
  39. },
  40. placement: {
  41. 'top right': 'top-4 right-4',
  42. 'top left': 'top-4 left-4',
  43. 'bottom right': 'bottom-4 right-4',
  44. 'bottom left': 'bottom-4 left-4',
  45. 'top center': 'top-4 self-center',
  46. 'bottom center': 'bottom-4 self-center',
  47. },
  48. },
  49. });
  50. const fabLabelStyle = tva({
  51. base: 'text-typography-50 font-normal font-body tracking-md text-left mx-2',
  52. variants: {
  53. isTruncated: {
  54. true: '',
  55. },
  56. bold: {
  57. true: 'font-bold',
  58. },
  59. underline: {
  60. true: 'underline',
  61. },
  62. strikeThrough: {
  63. true: 'line-through',
  64. },
  65. size: {
  66. '2xs': 'text-2xs',
  67. 'xs': 'text-xs',
  68. 'sm': 'text-sm',
  69. 'md': 'text-base',
  70. 'lg': 'text-lg',
  71. 'xl': 'text-xl',
  72. '2xl': 'text-2xl',
  73. '3xl': 'text-3xl',
  74. '4xl': 'text-4xl',
  75. '5xl': 'text-5xl',
  76. '6xl': 'text-6xl',
  77. },
  78. sub: {
  79. true: 'text-xs',
  80. },
  81. italic: {
  82. true: 'italic',
  83. },
  84. highlight: {
  85. true: 'bg-yellow-500',
  86. },
  87. },
  88. parentVariants: {
  89. size: {
  90. sm: 'text-sm',
  91. md: 'text-base',
  92. lg: 'text-lg',
  93. },
  94. },
  95. });
  96. const fabIconStyle = tva({
  97. base: 'text-typography-50 fill-none',
  98. variants: {
  99. size: {
  100. '2xs': 'h-3 w-3',
  101. 'xs': 'h-3.5 w-3.5',
  102. 'sm': 'h-4 w-4',
  103. 'md': 'w-[18px] h-[18px]',
  104. 'lg': 'h-5 w-5',
  105. 'xl': 'h-6 w-6',
  106. },
  107. },
  108. });
  109. type IFabProps = Omit<React.ComponentPropsWithoutRef<typeof UIFab>, 'context'> &
  110. VariantProps<typeof fabStyle>;
  111. const Fab = React.forwardRef<React.ComponentRef<typeof UIFab>, IFabProps>(
  112. function Fab(
  113. { size = 'md', placement = 'bottom right', className, ...props },
  114. ref
  115. ) {
  116. return (
  117. <UIFab
  118. ref={ref}
  119. {...props}
  120. className={fabStyle({ size, placement, class: className })}
  121. context={{ size }}
  122. />
  123. );
  124. }
  125. );
  126. type IFabLabelProps = React.ComponentPropsWithoutRef<typeof UIFab.Label> &
  127. VariantProps<typeof fabLabelStyle>;
  128. const FabLabel = React.forwardRef<
  129. React.ComponentRef<typeof UIFab.Label>,
  130. IFabLabelProps
  131. >(function FabLabel(
  132. {
  133. size,
  134. isTruncated = false,
  135. bold = false,
  136. underline = false,
  137. strikeThrough = false,
  138. className,
  139. ...props
  140. },
  141. ref
  142. ) {
  143. const { size: parentSize } = useStyleContext(SCOPE);
  144. return (
  145. <UIFab.Label
  146. ref={ref}
  147. {...props}
  148. className={fabLabelStyle({
  149. parentVariants: {
  150. size: parentSize,
  151. },
  152. size,
  153. isTruncated,
  154. bold,
  155. underline,
  156. strikeThrough,
  157. class: className,
  158. })}
  159. />
  160. );
  161. });
  162. type IFabIconProps = React.ComponentPropsWithoutRef<typeof UIFab.Icon> &
  163. VariantProps<typeof fabIconStyle> & {
  164. height?: number;
  165. width?: number;
  166. };
  167. const FabIcon = React.forwardRef<
  168. React.ComponentRef<typeof UIFab.Icon>,
  169. IFabIconProps
  170. >(function FabIcon({ size, className, ...props }, ref) {
  171. const { size: parentSize } = useStyleContext(SCOPE);
  172. if (typeof size === 'number') {
  173. return (
  174. <UIFab.Icon
  175. ref={ref}
  176. {...props}
  177. className={fabIconStyle({ class: className })}
  178. size={size}
  179. />
  180. );
  181. } else if (
  182. (props.height !== undefined || props.width !== undefined) &&
  183. size === undefined
  184. ) {
  185. return (
  186. <UIFab.Icon
  187. ref={ref}
  188. {...props}
  189. className={fabIconStyle({ class: className })}
  190. />
  191. );
  192. }
  193. return (
  194. <UIFab.Icon
  195. ref={ref}
  196. {...props}
  197. className={fabIconStyle({
  198. parentVariants: {
  199. size: parentSize,
  200. },
  201. size,
  202. class: className,
  203. })}
  204. />
  205. );
  206. });
  207. Fab.displayName = 'Fab';
  208. FabLabel.displayName = 'FabLabel';
  209. FabIcon.displayName = 'FabIcon';
  210. export { Fab, FabLabel, FabIcon };