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.8KB

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