index.tsx 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  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 as CheckIcon,
  21. Minus as MinusIcon
  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={stylesheet.emptyIcon}
  148. />;
  149. }
  150. const selectedColor = indicatorIconProps.customColor ? indicatorIconProps.customColor : colors.content.border[indicatorIconProps.color];
  151. if(isChecked === "partially") {
  152. return <MinusIcon
  153. color={selectedColor}
  154. size={16}
  155. />;
  156. }
  157. return <CheckIcon
  158. color={selectedColor}
  159. size={16}
  160. />;
  161. };
  162. const renderCheckIndicator = () => {
  163. if (isLoading) {
  164. return <Loading
  165. style={{
  166. ...loadingDynamicStyle
  167. }}
  168. />;
  169. }
  170. return <View
  171. style={[
  172. stylesheet.indicatorContainer,
  173. indicatorContainerDynamicStyle
  174. ]}
  175. >
  176. {renderCheckIcon()}
  177. {renderOverlay()}
  178. </View>;
  179. };
  180. const renderOverlay = () => {
  181. return <View
  182. style={[
  183. stylesheet.overlay,
  184. overlayDynamicStyle
  185. ]}
  186. />;
  187. };
  188. const renderSubtitle = () => {
  189. if(!subTitle) {
  190. return null;
  191. }
  192. return <Text
  193. {...subTitleProps}
  194. style={[
  195. subTitleStyle,
  196. stylesheet.subTitle,
  197. subTitleDynamicStyle
  198. ]}
  199. >
  200. {subTitle}
  201. </Text>;
  202. };
  203. const renderContent = () => {
  204. if(!title) {
  205. return null;
  206. }
  207. return <View
  208. style={[
  209. stylesheet.contentContainer,
  210. contentContainerDynamicStyle
  211. ]}
  212. >
  213. {renderTitle()}
  214. {renderSubtitle()}
  215. </View>;
  216. };
  217. return <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 : renderCheckIndicator()}
  236. {renderContent()}
  237. {isFlip ? renderCheckIndicator() : null}
  238. </TouchableOpacity>;
  239. };
  240. export default CheckBox;