index.tsx 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  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. const _customTextColor = customTextColor as keyof NCoreUIKit.ProjectColorPalette;
  122. iconProps.customColor = colors.project[_customTextColor] ? colors.project[_customTextColor] : customTextColor;
  123. }
  124. if(customIconColor) {
  125. const _customIconColor = customIconColor as keyof NCoreUIKit.ProjectColorPalette;
  126. iconProps.customColor = colors.project[_customIconColor] ? colors.project[_customIconColor] : customIconColor;
  127. }
  128. }
  129. if (isLoading) {
  130. if(renderLoading) {
  131. return renderLoading();
  132. }
  133. return <Loading
  134. {...iconProps}
  135. style={{
  136. ...loadingDynamicStyle
  137. }}
  138. />;
  139. }
  140. if (!IconComponentProp) {
  141. return null;
  142. }
  143. return <IconComponentProp {...iconProps} />;
  144. };
  145. const renderTitle = () => {
  146. if (!title) {
  147. return null;
  148. }
  149. if(!isDisabled && !isLoading) {
  150. if(customTextColor) {
  151. titleProps.customColor = customTextColor;
  152. }
  153. }
  154. return <Text
  155. variant={currentSize.fontSize}
  156. style={[
  157. titleStyle,
  158. stylesheet.title,
  159. titleDynamicStyle
  160. ]}
  161. {...titleProps}
  162. >
  163. {title}
  164. </Text>;
  165. };
  166. const renderOverlay = () => {
  167. return <View
  168. style={[
  169. stylesheet.loading,
  170. stylesheet.overlay,
  171. overlayDynamicStyle
  172. ]}
  173. />;
  174. };
  175. return <TouchableOpacity
  176. {...props}
  177. onPress={isDisabled || isLoading ? () => null : onPress}
  178. disabled={isDisabled || isLoading}
  179. style={[
  180. style,
  181. stylesheet.container,
  182. containerDynamicStyle
  183. ]}
  184. >
  185. {renderIcon()}
  186. {renderTitle()}
  187. {renderOverlay()}
  188. </TouchableOpacity>;
  189. };
  190. export default Button;