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

331 lines
7.7 KiB

  1. 'use client';
  2. import React from 'react';
  3. import { createAccordion } from '@gluestack-ui/accordion';
  4. import { View, Pressable, Text, Platform, TextProps } from 'react-native';
  5. import { tva } from '@gluestack-ui/nativewind-utils/tva';
  6. import type { VariantProps } from '@gluestack-ui/nativewind-utils';
  7. import {
  8. withStyleContext,
  9. useStyleContext,
  10. } from '@gluestack-ui/nativewind-utils/withStyleContext';
  11. import { H3 } from '@expo/html-elements';
  12. import { cssInterop } from 'nativewind';
  13. import { PrimitiveIcon, UIIcon } from '@gluestack-ui/icon';
  14. const SCOPE = 'ACCORDION';
  15. /** Styles */
  16. const accordionStyle = tva({
  17. base: 'w-full',
  18. variants: {
  19. variant: {
  20. filled: 'bg-white shadow-hard-2',
  21. unfilled: '',
  22. },
  23. size: {
  24. sm: '',
  25. md: '',
  26. lg: '',
  27. },
  28. },
  29. });
  30. const accordionItemStyle = tva({
  31. base: '',
  32. parentVariants: {
  33. variant: {
  34. filled: 'bg-background-0',
  35. unfilled: 'bg-transparent',
  36. },
  37. },
  38. });
  39. const accordionTitleTextStyle = tva({
  40. base: 'text-typography-900 font-bold flex-1 text-left',
  41. parentVariants: {
  42. size: {
  43. sm: 'text-sm',
  44. md: 'text-base',
  45. lg: 'text-lg',
  46. },
  47. },
  48. });
  49. const accordionIconStyle = tva({
  50. base: 'text-typography-900 fill-none',
  51. parentVariants: {
  52. size: {
  53. '2xs': 'h-3 w-3',
  54. 'xs': 'h-3.5 w-3.5',
  55. 'sm': 'h-4 w-4',
  56. 'md': 'h-[18px] w-[18px]',
  57. 'lg': 'h-5 w-5',
  58. 'xl': 'h-6 w-6',
  59. },
  60. },
  61. });
  62. const accordionContentTextStyle = tva({
  63. base: 'text-typography-700 font-normal',
  64. parentVariants: {
  65. size: {
  66. sm: 'text-sm',
  67. md: 'text-base',
  68. lg: 'text-lg',
  69. },
  70. },
  71. });
  72. const accordionHeaderStyle = tva({
  73. base: 'mx-0 my-0',
  74. });
  75. const accordionContentStyle = tva({
  76. base: 'pt-1 pb-3 px-4',
  77. });
  78. const accordionTriggerStyle = tva({
  79. base: 'w-full flex-row justify-between items-center web:outline-none focus:outline-none data-[disabled=true]:opacity-40 data-[disabled=true]:cursor-not-allowed data-[focus-visible=true]:bg-background-50 py-3 px-4',
  80. });
  81. const Root = withStyleContext(View, SCOPE);
  82. const Header = (
  83. Platform.OS === 'web' ? H3 : View
  84. ) as React.ComponentType<TextProps>;
  85. /** Creator */
  86. const UIAccordion = createAccordion({
  87. Root: Root,
  88. Item: View,
  89. Header: Header,
  90. Trigger: Pressable,
  91. Icon: UIIcon,
  92. TitleText: Text,
  93. ContentText: Text,
  94. Content: View,
  95. });
  96. cssInterop(PrimitiveIcon, {
  97. className: {
  98. target: 'style',
  99. nativeStyleToProp: {
  100. height: true,
  101. width: true,
  102. fill: true,
  103. color: 'classNameColor',
  104. stroke: true,
  105. },
  106. },
  107. });
  108. cssInterop(H3, {
  109. className: {
  110. target: 'style',
  111. },
  112. });
  113. type IAccordionProps = React.ComponentPropsWithoutRef<typeof UIAccordion> &
  114. VariantProps<typeof accordionStyle>;
  115. type IAccordionItemProps = React.ComponentPropsWithoutRef<
  116. typeof UIAccordion.Item
  117. > &
  118. VariantProps<typeof accordionItemStyle>;
  119. type IAccordionContentProps = React.ComponentPropsWithoutRef<
  120. typeof UIAccordion.Content
  121. > &
  122. VariantProps<typeof accordionContentStyle>;
  123. type IAccordionContentTextProps = React.ComponentPropsWithoutRef<
  124. typeof UIAccordion.ContentText
  125. > &
  126. VariantProps<typeof accordionContentTextStyle>;
  127. type IAccordionIconProps = VariantProps<typeof accordionIconStyle> &
  128. React.ComponentPropsWithoutRef<typeof UIAccordion.Icon> & {
  129. as?: React.ElementType;
  130. height?: number;
  131. width?: number;
  132. };
  133. type IAccordionHeaderProps = React.ComponentPropsWithoutRef<
  134. typeof UIAccordion.Header
  135. > &
  136. VariantProps<typeof accordionHeaderStyle>;
  137. type IAccordionTriggerProps = React.ComponentPropsWithoutRef<
  138. typeof UIAccordion.Trigger
  139. > &
  140. VariantProps<typeof accordionTriggerStyle>;
  141. type IAccordionTitleTextProps = React.ComponentPropsWithoutRef<
  142. typeof UIAccordion.TitleText
  143. > &
  144. VariantProps<typeof accordionTitleTextStyle>;
  145. /** Components */
  146. const Accordion = React.forwardRef<
  147. React.ComponentRef<typeof UIAccordion>,
  148. IAccordionProps
  149. >(({ className, variant = 'filled', size = 'md', ...props }, ref) => {
  150. return (
  151. <UIAccordion
  152. ref={ref}
  153. {...props}
  154. className={accordionStyle({ variant, class: className })}
  155. context={{ variant, size }}
  156. />
  157. );
  158. });
  159. const AccordionItem = React.forwardRef<
  160. React.ComponentRef<typeof UIAccordion.Item>,
  161. IAccordionItemProps
  162. >(({ className, ...props }, ref) => {
  163. const { variant } = useStyleContext(SCOPE);
  164. return (
  165. <UIAccordion.Item
  166. ref={ref}
  167. {...props}
  168. className={accordionItemStyle({
  169. parentVariants: { variant },
  170. class: className,
  171. })}
  172. />
  173. );
  174. });
  175. const AccordionContent = React.forwardRef<
  176. React.ComponentRef<typeof UIAccordion.Content>,
  177. IAccordionContentProps
  178. >(function AccordionContent({ className, ...props }, ref) {
  179. return (
  180. <UIAccordion.Content
  181. ref={ref}
  182. {...props}
  183. className={accordionContentStyle({
  184. class: className,
  185. })}
  186. />
  187. );
  188. });
  189. const AccordionContentText = React.forwardRef<
  190. React.ComponentRef<typeof UIAccordion.ContentText>,
  191. IAccordionContentTextProps
  192. >(function AccordionContentText({ className, ...props }, ref) {
  193. const { size } = useStyleContext(SCOPE);
  194. return (
  195. <UIAccordion.ContentText
  196. ref={ref}
  197. {...props}
  198. className={accordionContentTextStyle({
  199. parentVariants: { size },
  200. class: className,
  201. })}
  202. />
  203. );
  204. });
  205. const AccordionIcon = React.forwardRef<
  206. React.ComponentRef<typeof UIAccordion.Icon>,
  207. IAccordionIconProps
  208. >(function AccordionIcon({ size, className, ...props }, ref) {
  209. const { size: parentSize } = useStyleContext(SCOPE);
  210. if (typeof size === 'number') {
  211. return (
  212. <UIAccordion.Icon
  213. ref={ref}
  214. {...props}
  215. className={accordionIconStyle({ class: className })}
  216. size={size}
  217. />
  218. );
  219. } else if (
  220. (props.height !== undefined || props.width !== undefined) &&
  221. size === undefined
  222. ) {
  223. return (
  224. <UIAccordion.Icon
  225. ref={ref}
  226. {...props}
  227. className={accordionIconStyle({ class: className })}
  228. />
  229. );
  230. }
  231. return (
  232. <UIAccordion.Icon
  233. ref={ref}
  234. {...props}
  235. className={accordionIconStyle({
  236. size,
  237. class: className,
  238. parentVariants: { size: parentSize },
  239. })}
  240. />
  241. );
  242. });
  243. const AccordionHeader = React.forwardRef<
  244. React.ComponentRef<typeof UIAccordion.Header>,
  245. IAccordionHeaderProps
  246. >(function AccordionHeader({ className, ...props }, ref) {
  247. return (
  248. <UIAccordion.Header
  249. ref={ref}
  250. {...props}
  251. className={accordionHeaderStyle({
  252. class: className,
  253. })}
  254. />
  255. );
  256. });
  257. const AccordionTrigger = React.forwardRef<
  258. React.ComponentRef<typeof UIAccordion.Trigger>,
  259. IAccordionTriggerProps
  260. >(function AccordionTrigger({ className, ...props }, ref) {
  261. return (
  262. <UIAccordion.Trigger
  263. ref={ref}
  264. {...props}
  265. className={accordionTriggerStyle({
  266. class: className,
  267. })}
  268. />
  269. );
  270. });
  271. const AccordionTitleText = React.forwardRef<
  272. React.ComponentRef<typeof UIAccordion.TitleText>,
  273. IAccordionTitleTextProps
  274. >(function AccordionTitleText({ className, ...props }, ref) {
  275. const { size } = useStyleContext(SCOPE);
  276. return (
  277. <UIAccordion.TitleText
  278. ref={ref}
  279. {...props}
  280. className={accordionTitleTextStyle({
  281. parentVariants: { size },
  282. class: className,
  283. })}
  284. />
  285. );
  286. });
  287. Accordion.displayName = 'Accordion';
  288. AccordionItem.displayName = 'AccordionItem';
  289. AccordionHeader.displayName = 'AccordionHeader';
  290. AccordionTrigger.displayName = 'AccordionTrigger';
  291. AccordionTitleText.displayName = 'AccordionTitleText';
  292. AccordionContentText.displayName = 'AccordionContentText';
  293. AccordionIcon.displayName = 'AccordionIcon';
  294. AccordionContent.displayName = 'AccordionContent';
  295. export {
  296. Accordion,
  297. AccordionItem,
  298. AccordionHeader,
  299. AccordionTrigger,
  300. AccordionTitleText,
  301. AccordionContentText,
  302. AccordionIcon,
  303. AccordionContent,
  304. };