index.tsx 4.1 KB

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