您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

DeviceSelector.web.js 6.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. /* @flow */
  2. import DropdownMenu, {
  3. DropdownItem,
  4. DropdownItemGroup
  5. } from '@atlaskit/dropdown-menu';
  6. import React, { Component } from 'react';
  7. import { translate } from '../../base/i18n/functions';
  8. /**
  9. * The type of the React {@code Component} props of {@link DeviceSelector}.
  10. */
  11. type Props = {
  12. /**
  13. * MediaDeviceInfos used for display in the select element.
  14. */
  15. devices: Array<Object>,
  16. /**
  17. * If false, will return a selector with no selection options.
  18. */
  19. hasPermission: boolean,
  20. /**
  21. * CSS class for the icon to the left of the dropdown trigger.
  22. */
  23. icon: string,
  24. /**
  25. * If true, will render the selector disabled with a default selection.
  26. */
  27. isDisabled: boolean,
  28. /**
  29. * The translation key to display as a menu label.
  30. */
  31. label: string,
  32. /**
  33. * The callback to invoke when a selection is made.
  34. */
  35. onSelect: Function,
  36. /**
  37. * The default device to display as selected.
  38. */
  39. selectedDeviceId: string,
  40. /**
  41. * Invoked to obtain translated strings.
  42. */
  43. t: Function
  44. };
  45. /**
  46. * React component for selecting a device from a select element. Wraps
  47. * AKDropdownMenu with device selection specific logic.
  48. *
  49. * @extends Component
  50. */
  51. class DeviceSelector extends Component<Props> {
  52. /**
  53. * Initializes a new DeviceSelector instance.
  54. *
  55. * @param {Object} props - The read-only React Component props with which
  56. * the new instance is to be initialized.
  57. */
  58. constructor(props) {
  59. super(props);
  60. this._onSelect = this._onSelect.bind(this);
  61. this._createDropdownItem = this._createDropdownItem.bind(this);
  62. }
  63. /**
  64. * Implements React's {@link Component#render()}.
  65. *
  66. * @inheritdoc
  67. * @returns {ReactElement}
  68. */
  69. render() {
  70. if (!this.props.hasPermission) {
  71. return this._renderNoPermission();
  72. }
  73. if (!this.props.devices || !this.props.devices.length) {
  74. return this._renderNoDevices();
  75. }
  76. const items = this.props.devices.map(this._createDropdownItem);
  77. const defaultSelected = this.props.devices.find(item =>
  78. item.deviceId === this.props.selectedDeviceId
  79. );
  80. return this._createDropdown({
  81. defaultSelected,
  82. isDisabled: this.props.isDisabled,
  83. items,
  84. placeholder: this.props.t('deviceSelection.selectADevice')
  85. });
  86. }
  87. /**
  88. * Creates a React Element for displaying the passed in text surrounded by
  89. * two icons. The left icon is the icon class passed in through props and
  90. * the right icon is AtlasKit ExpandIcon.
  91. *
  92. * @param {string} triggerText - The text to display within the element.
  93. * @private
  94. * @returns {ReactElement}
  95. */
  96. _createDropdownTrigger(triggerText) {
  97. return (
  98. <div className = 'device-selector-trigger'>
  99. <span className = 'device-selector-trigger-text'>
  100. { triggerText }
  101. </span>
  102. </div>
  103. );
  104. }
  105. _createDropdownItem: (Object) => void;
  106. /**
  107. * Creates an object in the format expected by AKDropdownMenu for an option.
  108. *
  109. * @param {MediaDeviceInfo} device - An object with a label and a deviceId.
  110. * @private
  111. * @returns {Object} The passed in media device description converted to a
  112. * format recognized as a valid AKDropdownMenu item.
  113. */
  114. _createDropdownItem(device) {
  115. return (
  116. <DropdownItem
  117. key = { device.deviceId }
  118. // eslint-disable-next-line react/jsx-no-bind
  119. onClick = {
  120. e => {
  121. e.stopPropagation();
  122. this._onSelect(device.deviceId);
  123. }
  124. }>
  125. { device.label || device.deviceId }
  126. </DropdownItem>
  127. );
  128. }
  129. /**
  130. * Creates a AKDropdownMenu Component using passed in props and options. If
  131. * the dropdown needs to be disabled, then only the AKDropdownMenu trigger
  132. * element is returned to simulate a disabled state.
  133. *
  134. * @param {Object} options - Additional configuration for display.
  135. * @param {Object} options.defaultSelected - The option that should be set
  136. * as currently chosen.
  137. * @param {boolean} options.isDisabled - If true, only the AKDropdownMenu
  138. * trigger component will be returned to simulate a disabled dropdown.
  139. * @param {Array} options.items - All the selectable options to display.
  140. * @param {string} options.placeholder - The translation key to display when
  141. * no selection has been made.
  142. * @private
  143. * @returns {ReactElement}
  144. */
  145. _createDropdown(options) {
  146. const triggerText
  147. = (options.defaultSelected && (options.defaultSelected.label || options.defaultSelected.deviceId))
  148. || options.placeholder;
  149. const trigger = this._createDropdownTrigger(triggerText);
  150. if (options.isDisabled || !options.items.length) {
  151. return (
  152. <div className = 'device-selector-trigger-disabled'>
  153. { trigger }
  154. </div>
  155. );
  156. }
  157. return (
  158. <div className = 'dropdown-menu'>
  159. <DropdownMenu
  160. shouldFitContainer = { true }
  161. trigger = { triggerText }
  162. triggerButtonProps = {{
  163. shouldFitContainer: true
  164. }}
  165. triggerType = 'button'>
  166. <DropdownItemGroup>
  167. { options.items }
  168. </DropdownItemGroup>
  169. </DropdownMenu>
  170. </div>
  171. );
  172. }
  173. _onSelect: (Object) => void;
  174. /**
  175. * Invokes the passed in callback to notify of selection changes.
  176. *
  177. * @param {Object} newDeviceId - Selected device id from DropdownMenu option.
  178. * @private
  179. * @returns {void}
  180. */
  181. _onSelect(newDeviceId) {
  182. if (this.props.selectedDeviceId !== newDeviceId) {
  183. this.props.onSelect(newDeviceId);
  184. }
  185. }
  186. /**
  187. * Creates a Select Component that is disabled and has a placeholder
  188. * indicating there are no devices to select.
  189. *
  190. * @private
  191. * @returns {ReactElement}
  192. */
  193. _renderNoDevices() {
  194. return this._createDropdown({
  195. isDisabled: true,
  196. placeholder: this.props.t('settings.noDevice')
  197. });
  198. }
  199. /**
  200. * Creates a AKDropdownMenu Component that is disabled and has a placeholder
  201. * stating there is no permission to display the devices.
  202. *
  203. * @private
  204. * @returns {ReactElement}
  205. */
  206. _renderNoPermission() {
  207. return this._createDropdown({
  208. isDisabled: true,
  209. placeholder: this.props.t('deviceSelection.noPermission')
  210. });
  211. }
  212. }
  213. export default translate(DeviceSelector);