index.tsx 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. import {
  2. type FC
  3. } from "react";
  4. import {
  5. TouchableOpacity,
  6. View
  7. } from "react-native";
  8. import type IButtonProps from "./type";
  9. import stylesheet, {
  10. getButtonVariant,
  11. getButtonSize,
  12. getButtonType,
  13. useStyles
  14. } from "./stylesheet";
  15. import {
  16. NCoreUIKitTheme
  17. } from "../../core/hooks";
  18. import type ITextProps from "../text/type";
  19. import Loading from "../loading";
  20. import Text from "../text";
  21. /**
  22. * A generic button
  23. * @param props {@link IButtonProps}
  24. * @returns Element
  25. */
  26. const Button: FC<IButtonProps> = ({
  27. displayBehaviourWhileLoading = "disabled",
  28. spreadBehaviour = "baseline",
  29. isCustomPadding = false,
  30. icon: IconComponentProp,
  31. iconDirection = "left",
  32. variant = "filled",
  33. isDisabled = false,
  34. customBorderColor,
  35. type = "primary",
  36. customIconColor,
  37. customTextColor,
  38. size = "medium",
  39. renderLoading,
  40. customColor,
  41. customTheme,
  42. titleStyle,
  43. isLoading,
  44. onPress,
  45. title,
  46. style,
  47. ...props
  48. }) => {
  49. const {
  50. typography,
  51. radiuses,
  52. borders,
  53. colors,
  54. spaces
  55. } = NCoreUIKitTheme.useContext(customTheme);
  56. const currentSize = getButtonSize({
  57. spaces,
  58. size
  59. });
  60. const currentVariant = getButtonVariant({
  61. variant,
  62. });
  63. const currentType = getButtonType({
  64. type,
  65. });
  66. const {
  67. container: containerDynamicStyle,
  68. loading: loadingDynamicStyle,
  69. overlay: overlayDynamicStyle,
  70. title: titleDynamicStyle
  71. } = useStyles({
  72. displayBehaviourWhileLoading,
  73. icon: IconComponentProp,
  74. customBorderColor,
  75. isCustomPadding,
  76. spreadBehaviour,
  77. currentVariant,
  78. iconDirection,
  79. currentType,
  80. currentSize,
  81. customColor,
  82. isDisabled,
  83. isLoading,
  84. radiuses,
  85. variant,
  86. borders,
  87. colors,
  88. spaces,
  89. title,
  90. type
  91. });
  92. const titleProps: ITextProps = {
  93. color: currentType.titleColor,
  94. };
  95. const iconProps: NCoreUIKit.IconCallbackProps = {
  96. size: Number(typography[currentSize.fontSize].fontSize),
  97. color: currentType.iconColor
  98. };
  99. if (currentVariant.titleColor !== "type") {
  100. titleProps.color = currentType.titleColor;
  101. }
  102. if (currentVariant.iconColor !== "type") {
  103. iconProps.color = currentType.iconColor;
  104. }
  105. if (type === "primary" && variant === "filled") {
  106. iconProps.color = "onPrimary";
  107. titleProps.color = "onPrimary";
  108. }
  109. if (type === "primary" && variant !== "filled") {
  110. iconProps.color = "emphasized";
  111. titleProps.color = "emphasized";
  112. }
  113. if (isDisabled || isLoading) {
  114. const stateType = type === "danger" ? "error" : type;
  115. titleProps.customColor = colors.system.state.content.disabled[stateType];
  116. iconProps.customColor = colors.system.state.content.disabled[stateType];
  117. }
  118. const renderIcon = () => {
  119. if(!isDisabled && !isLoading) {
  120. if(customTextColor) {
  121. iconProps.customColor = customTextColor;
  122. }
  123. if(customIconColor) {
  124. iconProps.customColor = customIconColor;
  125. }
  126. }
  127. if (isLoading) {
  128. if(renderLoading) {
  129. return renderLoading();
  130. }
  131. return <Loading
  132. {...iconProps}
  133. style={[
  134. loadingDynamicStyle
  135. ]}
  136. />;
  137. }
  138. if (!IconComponentProp) {
  139. return null;
  140. }
  141. return <IconComponentProp {...iconProps} />;
  142. };
  143. const renderTitle = () => {
  144. if (!title) {
  145. return null;
  146. }
  147. if(!isDisabled && !isLoading) {
  148. if(customTextColor) {
  149. titleProps.customColor = customTextColor;
  150. }
  151. }
  152. return <Text
  153. variant={currentSize.fontSize}
  154. style={[
  155. titleStyle,
  156. stylesheet.title,
  157. titleDynamicStyle
  158. ]}
  159. {...titleProps}
  160. >
  161. {title}
  162. </Text>;
  163. };
  164. const renderOverlay = () => {
  165. return <View
  166. style={[
  167. stylesheet.loading,
  168. stylesheet.overlay,
  169. overlayDynamicStyle
  170. ]}
  171. />;
  172. };
  173. return <TouchableOpacity
  174. {...props}
  175. onPress={isDisabled || isLoading ? () => null : onPress}
  176. disabled={isDisabled || isLoading}
  177. style={[
  178. style,
  179. stylesheet.container,
  180. containerDynamicStyle
  181. ]}
  182. >
  183. {renderIcon()}
  184. {renderTitle()}
  185. {renderOverlay()}
  186. </TouchableOpacity>;
  187. };
  188. export default Button;