You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ToolButton.tsx 3.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. import "./ToolIcon.scss";
  2. import React from "react";
  3. import clsx from "clsx";
  4. type ToolIconSize = "s" | "m";
  5. type ToolButtonBaseProps = {
  6. icon?: React.ReactNode;
  7. "aria-label": string;
  8. "aria-keyshortcuts"?: string;
  9. "data-testid"?: string;
  10. label?: string;
  11. title?: string;
  12. name?: string;
  13. id?: string;
  14. size?: ToolIconSize;
  15. keyBindingLabel?: string;
  16. showAriaLabel?: boolean;
  17. hidden?: boolean;
  18. visible?: boolean;
  19. selected?: boolean;
  20. className?: string;
  21. };
  22. type ToolButtonProps =
  23. | (ToolButtonBaseProps & {
  24. type: "button";
  25. children?: React.ReactNode;
  26. onClick?(): void;
  27. })
  28. | (ToolButtonBaseProps & {
  29. type: "icon";
  30. children?: React.ReactNode;
  31. onClick?(): void;
  32. })
  33. | (ToolButtonBaseProps & {
  34. type: "radio";
  35. checked: boolean;
  36. onChange?(): void;
  37. });
  38. const DEFAULT_SIZE: ToolIconSize = "m";
  39. export const ToolButton = React.forwardRef((props: ToolButtonProps, ref) => {
  40. const innerRef = React.useRef(null);
  41. React.useImperativeHandle(ref, () => innerRef.current);
  42. const sizeCn = `ToolIcon_size_${props.size || DEFAULT_SIZE}`;
  43. if (props.type === "button" || props.type === "icon") {
  44. return (
  45. <button
  46. className={clsx(
  47. "ToolIcon_type_button",
  48. sizeCn,
  49. props.className,
  50. props.visible && !props.hidden
  51. ? "ToolIcon_type_button--show"
  52. : "ToolIcon_type_button--hide",
  53. {
  54. ToolIcon: !props.hidden,
  55. "ToolIcon--selected": props.selected,
  56. "ToolIcon--plain": props.type === "icon",
  57. },
  58. )}
  59. data-testid={props["data-testid"]}
  60. hidden={props.hidden}
  61. title={props.title}
  62. aria-label={props["aria-label"]}
  63. type="button"
  64. onClick={props.onClick}
  65. ref={innerRef}
  66. >
  67. {(props.icon || props.label) && (
  68. <div className="ToolIcon__icon" aria-hidden="true">
  69. {props.icon || props.label}
  70. {props.keyBindingLabel && (
  71. <span className="ToolIcon__keybinding">
  72. {props.keyBindingLabel}
  73. </span>
  74. )}
  75. </div>
  76. )}
  77. {props.showAriaLabel && (
  78. <div className="ToolIcon__label">{props["aria-label"]}</div>
  79. )}
  80. {props.children}
  81. </button>
  82. );
  83. }
  84. return (
  85. <label className={clsx("ToolIcon", props.className)} title={props.title}>
  86. <input
  87. className={`ToolIcon_type_radio ${sizeCn}`}
  88. type="radio"
  89. name={props.name}
  90. aria-label={props["aria-label"]}
  91. aria-keyshortcuts={props["aria-keyshortcuts"]}
  92. data-testid={props["data-testid"]}
  93. id={props.id}
  94. onChange={props.onChange}
  95. checked={props.checked}
  96. ref={innerRef}
  97. />
  98. <div className="ToolIcon__icon">
  99. {props.icon}
  100. {props.keyBindingLabel && (
  101. <span className="ToolIcon__keybinding">{props.keyBindingLabel}</span>
  102. )}
  103. </div>
  104. </label>
  105. );
  106. });
  107. ToolButton.defaultProps = {
  108. visible: true,
  109. className: "",
  110. };