index.tsx 6.4 KB

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