summaryrefslogtreecommitdiff
path: root/src/components/Button.tsx
blob: 8c0acc6944e2bac58925ec99f64d7c18c2e05152 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import * as React from 'react';
import cx from 'clsx';

import { LoadingDot } from './shared/Basic';

import s0 from './Button.module.css';

const { memo, forwardRef, useCallback } = React;

type ButtonInternalProps = {
  children?: React.ReactChildren;
  label?: string;
  text?: string;
  start?: React.ReactElement | (() => React.ReactElement);
};

type ButtonProps = {
  isLoading?: boolean;
  onClick?: (e: React.MouseEvent<HTMLButtonElement>) => unknown;
  kind?: 'primary' | 'minimal';
  className?: string;
} & ButtonInternalProps;

function Button(props: ButtonProps, ref: React.Ref<HTMLButtonElement>) {
  const {
    onClick,
    isLoading,
    kind = 'primary',
    className,
    ...restProps
  } = props;
  const internalOnClick = useCallback(
    (e) => {
      if (isLoading) return;
      onClick && onClick(e);
    },
    [isLoading, onClick]
  );
  const btnClassName = cx(
    s0.btn,
    {
      [s0.minimal]: kind === 'minimal',
    },
    className
  );
  return (
    <button className={btnClassName} ref={ref} onClick={internalOnClick}>
      {isLoading ? (
        <>
          <span
            style={{
              display: 'inline-flex',
              opacity: 0,
            }}
          >
            <ButtonInternal {...restProps} />
          </span>
          <span className={s0.loadingContainer}>
            <LoadingDot />
          </span>
        </>
      ) : (
        <ButtonInternal {...restProps} />
      )}
    </button>
  );
}

function ButtonInternal({ children, label, text, start }: ButtonInternalProps) {
  return (
    <>
      {start ? (
        <span className={s0.btnStart}>
          {typeof start === 'function' ? start() : start}
        </span>
      ) : null}
      {children || label || text}
    </>
  );
}

export default memo(forwardRef(Button));