index.tsx 6.0 KB

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