ds-button.tsx 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. import { forwardRef, ReactNode } from 'react'
  2. import { Button, ButtonProps, Spinner } from 'react-bootstrap'
  3. import { useTranslation } from 'react-i18next'
  4. import classNames from 'classnames'
  5. type DSButtonProps = Pick<
  6. ButtonProps,
  7. | 'children'
  8. | 'className'
  9. | 'disabled'
  10. | 'href'
  11. | 'id'
  12. | 'target'
  13. | 'rel'
  14. | 'onClick'
  15. | 'onMouseDown'
  16. | 'onMouseOver'
  17. | 'onMouseOut'
  18. | 'onFocus'
  19. | 'onBlur'
  20. | 'size'
  21. | 'active'
  22. | 'type'
  23. > & {
  24. leadingIcon?: ReactNode
  25. trailingIcon?: ReactNode
  26. variant?: 'primary' | 'secondary' | 'tertiary' | 'danger'
  27. isLoading?: boolean
  28. loadingLabel?: string
  29. }
  30. const DSButton = forwardRef<HTMLButtonElement, DSButtonProps>(
  31. (
  32. {
  33. children,
  34. className,
  35. leadingIcon,
  36. isLoading = false,
  37. loadingLabel,
  38. trailingIcon,
  39. variant = 'primary',
  40. size,
  41. ...props
  42. },
  43. ref
  44. ) => {
  45. const { t } = useTranslation()
  46. const buttonClassName = classNames('d-inline-grid btn-ds', className, {
  47. 'button-loading': isLoading,
  48. })
  49. const loadingSpinnerClassName =
  50. size === 'lg' ? 'loading-spinner-large' : 'loading-spinner-small'
  51. return (
  52. <Button
  53. className={buttonClassName}
  54. variant={variant}
  55. size={size}
  56. {...props}
  57. ref={ref}
  58. disabled={isLoading || props.disabled}
  59. data-ol-loading={isLoading}
  60. role={undefined}
  61. >
  62. {isLoading && (
  63. <span className="spinner-container">
  64. <Spinner
  65. size="sm"
  66. animation="border"
  67. aria-hidden="true"
  68. className={loadingSpinnerClassName}
  69. />
  70. <span className="visually-hidden">
  71. {loadingLabel ?? t('loading')}
  72. </span>
  73. </span>
  74. )}
  75. <span className="button-content" aria-hidden={isLoading}>
  76. {leadingIcon}
  77. {children}
  78. {trailingIcon}
  79. </span>
  80. </Button>
  81. )
  82. }
  83. )
  84. DSButton.displayName = 'DSButton'
  85. export default DSButton