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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  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 name of the icon of this button, when toggled.
  60. *
  61. * @abstract
  62. */
  63. toggledIconName: string;
  64. /**
  65. * The text to display in the tooltip. Used only on web.
  66. *
  67. * @abstract
  68. */
  69. tooltip: string;
  70. /**
  71. * Initializes a new {@code AbstractButton} instance.
  72. *
  73. * @param {Props} props - The React {@code Component} props to initialize
  74. * the new {@code AbstractButton} instance with.
  75. */
  76. constructor(props: P) {
  77. super(props);
  78. // Bind event handlers so they are only bound once per instance.
  79. this._onClick = this._onClick.bind(this);
  80. }
  81. /**
  82. * Helper function to be implemented by subclasses, which should be used
  83. * to handle the button being clicked / pressed.
  84. *
  85. * @protected
  86. * @returns {void}
  87. */
  88. _handleClick() {
  89. // To be implemented by subclass.
  90. }
  91. /**
  92. * Gets the current icon name, taking the toggled state into account. If no
  93. * toggled icon is provided, the regular icon will also be used in the
  94. * toggled state.
  95. *
  96. * @private
  97. * @returns {string}
  98. */
  99. _getIconName() {
  100. return (this._isToggled() ? this.toggledIconName : this.iconName)
  101. || this.iconName;
  102. }
  103. /**
  104. * Gets the current styles, taking the toggled state into account. If no
  105. * toggled styles are provided, the regular styles will also be used in the
  106. * toggled state.
  107. *
  108. * @private
  109. * @returns {?Styles}
  110. */
  111. _getStyles() {
  112. const { styles, toggledStyles } = this.props;
  113. return (this._isToggled() ? toggledStyles : styles) || styles;
  114. }
  115. /**
  116. * Helper function to be implemented by subclasses, which must return a
  117. * boolean value indicating if this button is disabled or not.
  118. *
  119. * @protected
  120. * @returns {boolean}
  121. */
  122. _isDisabled() {
  123. return false;
  124. }
  125. /**
  126. * Helper function to be implemented by subclasses, which must return a
  127. * {@code boolean} value indicating if this button is toggled or not.
  128. *
  129. * @protected
  130. * @returns {boolean}
  131. */
  132. _isToggled() {
  133. return false;
  134. }
  135. _onClick: (*) => void;
  136. /**
  137. * Handles clicking / pressing the button, and toggles the audio mute state
  138. * accordingly.
  139. *
  140. * @private
  141. * @returns {void}
  142. */
  143. _onClick() {
  144. this._handleClick();
  145. }
  146. /**
  147. * Implements React's {@link Component#render()}.
  148. *
  149. * @inheritdoc
  150. * @returns {React$Node}
  151. */
  152. render(): React$Node {
  153. const props = {
  154. ...this.props,
  155. accessibilityLabel: this.accessibilityLabel,
  156. iconName: this._getIconName(),
  157. label: this.label,
  158. styles: this._getStyles(),
  159. tooltip: this.tooltip
  160. };
  161. return (
  162. <ToolboxItem
  163. disabled = { this._isDisabled() }
  164. onClick = { this._onClick }
  165. { ...props } />
  166. );
  167. }
  168. }