index.tsx 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. import {
  2. type FC
  3. } from "react";
  4. import {
  5. TouchableOpacity,
  6. Platform,
  7. View
  8. } from "react-native";
  9. import type IRadioButtonProps from "./type";
  10. import stylesheet, {
  11. getRadioButtonType,
  12. useStyles
  13. } from "./stylesheet";
  14. import {
  15. NCoreUIKitLocalize,
  16. NCoreUIKitTheme
  17. } from "../../core/hooks";
  18. import type ITextProps from "../text/type";
  19. import Loading from "../loading";
  20. import Text from "../text";
  21. const RadioButton: FC<IRadioButtonProps> = ({
  22. displayBehaviourWhileLoading = "disabled",
  23. spreadBehaviour = "baseline",
  24. isOptional = false,
  25. isDisabled = false,
  26. type = "neutral",
  27. isFlip = false,
  28. customLocalize,
  29. subTitleStyle,
  30. optionalText,
  31. customTheme,
  32. titleStyle,
  33. isChecked,
  34. isLoading,
  35. subTitle,
  36. onPress,
  37. title,
  38. style,
  39. ...props
  40. }) => {
  41. const {
  42. inlineSpaces,
  43. radiuses,
  44. borders,
  45. colors,
  46. spaces
  47. } = NCoreUIKitTheme.useContext(customTheme);
  48. const {
  49. localize
  50. } = NCoreUIKitLocalize.useContext(customLocalize);
  51. const currentType = getRadioButtonType({
  52. type
  53. });
  54. const RADIO_INDICATOR_SIZE = 16;
  55. const {
  56. indicatorContainer: indicatorContainerDynamicStyle,
  57. contentContainer: contentContainerDynamicStyle,
  58. titleContainer: titleContainerDynamicStyle,
  59. optionalText: optionalTextDynamicStyle,
  60. container: containerDynamicStyle,
  61. indicator: indicatorDynamicStyle,
  62. subTitle: subTitleDynamicStyle,
  63. loading: loadingDynamicStyle,
  64. overlay: overlayDynamicStyle,
  65. title: titleDynamicStyle
  66. } = useStyles({
  67. displayBehaviourWhileLoading,
  68. RADIO_INDICATOR_SIZE,
  69. spreadBehaviour,
  70. inlineSpaces,
  71. currentType,
  72. isDisabled,
  73. isChecked,
  74. isLoading,
  75. radiuses,
  76. borders,
  77. isFlip,
  78. colors,
  79. spaces,
  80. type
  81. });
  82. const titleProps: ITextProps = {
  83. color: currentType.titleColor,
  84. };
  85. const subTitleProps: ITextProps = {
  86. color: currentType.subTitleColor,
  87. };
  88. const indicatorIconProps: {
  89. color: keyof NCoreUIKit.IconContentColors;
  90. customColor?: string;
  91. } = {
  92. color: currentType.indicatorColor
  93. };
  94. if (isDisabled || isLoading) {
  95. const stateType = type === "danger" ? "error" : type;
  96. subTitleProps.customColor = colors.system.state.content.disabled[stateType];
  97. titleProps.customColor = colors.system.state.content.disabled[stateType];
  98. if(isChecked && stateType === "neutral") {
  99. indicatorIconProps.customColor = colors.system.state.border.disabled.primary;
  100. } else {
  101. indicatorIconProps.customColor = colors.system.state.border.disabled[stateType];
  102. }
  103. }
  104. const renderOptionalText = () => {
  105. if(!isOptional && !optionalText) {
  106. return null;
  107. }
  108. return <Text
  109. variant="labelLargeSize"
  110. color={titleProps.color}
  111. style={[
  112. optionalTextDynamicStyle
  113. ]}
  114. {...titleProps}
  115. >
  116. ( {isOptional ? localize("is-optional") : optionalText} )
  117. </Text>;
  118. };
  119. const renderTitle = () => {
  120. if (!title) {
  121. return null;
  122. }
  123. return <View
  124. style={[
  125. stylesheet.titleContainer,
  126. titleContainerDynamicStyle
  127. ]}
  128. >
  129. <Text
  130. variant="bodyMediumSize"
  131. style={[
  132. titleStyle,
  133. stylesheet.title,
  134. titleDynamicStyle
  135. ]}
  136. {...titleProps}
  137. >
  138. {title}
  139. </Text>
  140. {renderOptionalText()}
  141. </View>;
  142. };
  143. const renderIndicator = () => {
  144. if(!isChecked) {
  145. return <View
  146. style={[
  147. indicatorDynamicStyle,
  148. {
  149. backgroundColor: "transparent"
  150. }
  151. ]}
  152. />;
  153. }
  154. return <View
  155. style={[
  156. stylesheet.indicator,
  157. indicatorDynamicStyle
  158. ]}
  159. />;
  160. };
  161. const renderIndicatorContainer = () => {
  162. if (isLoading) {
  163. return <Loading
  164. style={{
  165. ...loadingDynamicStyle
  166. }}
  167. />;
  168. }
  169. return <View
  170. style={[
  171. stylesheet.indicatorContainer,
  172. indicatorContainerDynamicStyle
  173. ]}
  174. >
  175. {renderIndicator()}
  176. {renderOverlay()}
  177. </View>;
  178. };
  179. const renderOverlay = () => {
  180. return <View
  181. style={[
  182. stylesheet.overlay,
  183. overlayDynamicStyle
  184. ]}
  185. />;
  186. };
  187. const renderSubtitle = () => {
  188. if(!subTitle) {
  189. return null;
  190. }
  191. return <Text
  192. {...subTitleProps}
  193. style={[
  194. subTitleStyle,
  195. stylesheet.subTitle,
  196. subTitleDynamicStyle
  197. ]}
  198. >
  199. {subTitle}
  200. </Text>;
  201. };
  202. const renderContent = () => {
  203. if(!title) {
  204. return null;
  205. }
  206. return <View
  207. style={[
  208. stylesheet.contentContainer,
  209. contentContainerDynamicStyle
  210. ]}
  211. >
  212. {renderTitle()}
  213. {renderSubtitle()}
  214. </View>;
  215. };
  216. return (
  217. <TouchableOpacity
  218. {...props}
  219. onPress={isDisabled || isLoading ? () => null : onPress ? onPress : undefined}
  220. disabled={isDisabled || isLoading || !onPress}
  221. style={[
  222. style,
  223. stylesheet.container,
  224. containerDynamicStyle
  225. ]}
  226. {...Platform.select({
  227. web: {
  228. dataSet: {
  229. disablePressableDownEffect: "true"
  230. }
  231. },
  232. default: {}
  233. })}
  234. >
  235. {isFlip ? null : renderIndicatorContainer()}
  236. {renderContent()}
  237. {isFlip ? renderIndicatorContainer() : null}
  238. </TouchableOpacity>
  239. );
  240. };
  241. export default RadioButton;