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.

AbstractButton.js 4.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. // @flow
  2. import React, { Component } from 'react';
  3. import type { Styles } from './AbstractToolboxItem';
  4. import ToolboxItem from './ToolboxItem';
  5. export type Props = {
  6. /**
  7. * Function to be called after the click handler has been processed.
  8. */
  9. afterClick: ?Function,
  10. /**
  11. * Whether to show the label or not.
  12. */
  13. showLabel: boolean,
  14. /**
  15. * Collection of styles for the button.
  16. */
  17. styles: ?Styles,
  18. /**
  19. * Collection of styles for the button, when in toggled state.
  20. */
  21. toggledStyles: ?Styles,
  22. /**
  23. * From which direction the tooltip should appear, relative to the button.
  24. */
  25. tooltipPosition: string,
  26. /**
  27. * Whether this button is visible or not.
  28. */
  29. visible: boolean
  30. };
  31. /**
  32. * An abstract implementation of a button.
  33. */
  34. export default class AbstractButton<P: Props, S: *> extends Component<P, S> {
  35. static defaultProps = {
  36. afterClick: undefined,
  37. showLabel: false,
  38. styles: undefined,
  39. toggledStyles: undefined,
  40. tooltipPosition: 'top',
  41. visible: true
  42. };
  43. /**
  44. * A succinct description of what the button does. Used by accessibility
  45. * tools and torture tests.
  46. *
  47. * @abstract
  48. */
  49. accessibilityLabel: string;
  50. /**
  51. * The name of the icon of this button.
  52. *
  53. * @abstract
  54. */
  55. iconName: string;
  56. /**
  57. * The text associated with this button. When `showLabel` is set to
  58. * {@code true}, it will be displayed alongside the icon.
  59. *
  60. * @abstract
  61. */
  62. label: string;
  63. /**
  64. * The name of the icon of this button, when toggled.
  65. *
  66. * @abstract
  67. */
  68. toggledIconName: string;
  69. /**
  70. * The text to display in the tooltip. Used only on web.
  71. *
  72. * @abstract
  73. */
  74. tooltip: string;
  75. /**
  76. * Initializes a new {@code AbstractButton} instance.
  77. *
  78. * @param {Props} props - The React {@code Component} props to initialize
  79. * the new {@code AbstractButton} instance with.
  80. */
  81. constructor(props: P) {
  82. super(props);
  83. // Bind event handlers so they are only bound once per instance.
  84. this._onClick = this._onClick.bind(this);
  85. }
  86. /**
  87. * Helper function to be implemented by subclasses, which should be used
  88. * to handle the button being clicked / pressed.
  89. *
  90. * @protected
  91. * @returns {void}
  92. */
  93. _handleClick() {
  94. // To be implemented by subclass.
  95. }
  96. /**
  97. * Gets the current icon name, taking the toggled state into account. If no
  98. * toggled icon is provided, the regular icon will also be used in the
  99. * toggled state.
  100. *
  101. * @private
  102. * @returns {string}
  103. */
  104. _getIconName() {
  105. return (this._isToggled() ? this.toggledIconName : this.iconName)
  106. || this.iconName;
  107. }
  108. /**
  109. * Gets the current styles, taking the toggled state into account. If no
  110. * toggled styles are provided, the regular styles will also be used in the
  111. * toggled state.
  112. *
  113. * @private
  114. * @returns {?Styles}
  115. */
  116. _getStyles() {
  117. const { styles, toggledStyles } = this.props;
  118. return (this._isToggled() ? toggledStyles : styles) || styles;
  119. }
  120. /**
  121. * Helper function to be implemented by subclasses, which must return a
  122. * boolean value indicating if this button is disabled or not.
  123. *
  124. * @protected
  125. * @returns {boolean}
  126. */
  127. _isDisabled() {
  128. return false;
  129. }
  130. /**
  131. * Helper function to be implemented by subclasses, which must return a
  132. * {@code boolean} value indicating if this button is toggled or not.
  133. *
  134. * @protected
  135. * @returns {boolean}
  136. */
  137. _isToggled() {
  138. return false;
  139. }
  140. _onClick: (*) => void;
  141. /**
  142. * Handles clicking / pressing the button, and toggles the audio mute state
  143. * accordingly.
  144. *
  145. * @private
  146. * @returns {void}
  147. */
  148. _onClick() {
  149. const { afterClick } = this.props;
  150. this._handleClick();
  151. afterClick && afterClick();
  152. }
  153. /**
  154. * Implements React's {@link Component#render()}.
  155. *
  156. * @inheritdoc
  157. * @returns {React$Node}
  158. */
  159. render(): React$Node {
  160. const props = {
  161. ...this.props,
  162. accessibilityLabel: this.accessibilityLabel,
  163. iconName: this._getIconName(),
  164. label: this.label,
  165. styles: this._getStyles(),
  166. tooltip: this.tooltip
  167. };
  168. return (
  169. <ToolboxItem
  170. disabled = { this._isDisabled() }
  171. onClick = { this._onClick }
  172. { ...props } />
  173. );
  174. }
  175. }