DashboardCardMenu.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. /*
  2. * Copyright (C) 2017 - present Instructure, Inc.
  3. *
  4. * This file is part of Canvas.
  5. *
  6. * Canvas is free software: you can redistribute it and/or modify it under
  7. * the terms of the GNU Affero General Public License as published by the Free
  8. * Software Foundation, version 3 of the License.
  9. *
  10. * Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
  11. * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  13. * details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License along
  16. * with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. import React from 'react'
  19. import PropTypes from 'prop-types'
  20. import I18n from 'i18n!dashcards'
  21. import Popover, {PopoverTrigger, PopoverContent} from 'instructure-ui/lib/components/Popover'
  22. import TabList, {TabPanel} from 'instructure-ui/lib/components/TabList'
  23. import ColorPicker from 'jsx/shared/ColorPicker'
  24. import DashboardCardMovementMenu from './DashboardCardMovementMenu'
  25. export default class DashboardCardMenu extends React.Component {
  26. static propTypes = {
  27. afterUpdateColor: PropTypes.func.isRequired,
  28. currentColor: PropTypes.string.isRequired,
  29. nicknameInfo: PropTypes.shape({
  30. nickname: PropTypes.string,
  31. originalName: PropTypes.string,
  32. courseId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
  33. onNicknameChange: PropTypes.func
  34. }).isRequired,
  35. trigger: PropTypes.node.isRequired,
  36. assetString: PropTypes.string.isRequired,
  37. applicationElement: PropTypes.func,
  38. reorderingEnabled: PropTypes.bool,
  39. popoverContentRef: PropTypes.func,
  40. handleShow: PropTypes.func,
  41. handleMove: PropTypes.func,
  42. currentPosition: PropTypes.number,
  43. lastPosition: PropTypes.number,
  44. menuOptions: PropTypes.shape({
  45. canMoveLeft: PropTypes.bool,
  46. canMoveRight: PropTypes.bool,
  47. canMoveToBeginning: PropTypes.bool,
  48. canMoveToEnd: PropTypes.bool
  49. })
  50. }
  51. static defaultProps = {
  52. applicationElement: () => document.getElementById('application'),
  53. reorderingEnabled: false,
  54. popoverContentRef: () => {},
  55. handleShow: () => {},
  56. handleMove: () => {},
  57. currentPosition: 0,
  58. lastPosition: 0,
  59. menuOptions: null
  60. }
  61. constructor (props) {
  62. super(props)
  63. this.state = {
  64. show: false
  65. }
  66. this._closeButton = null
  67. this._colorTab = null
  68. // for testing
  69. this._movementMenu = null
  70. this._colorPicker = null
  71. this._tabList = null
  72. }
  73. shouldComponentUpdate(nextProps, nextState) {
  74. // Don't rerender the popover every time the color changes
  75. // only when we open and close (flashes on each color select otherwise)
  76. return (this.state !== nextState)
  77. }
  78. handleMenuToggle = (show) => {
  79. this.setState({ show })
  80. }
  81. handleClose = () => {
  82. this.setState({show: false})
  83. }
  84. handleMovementMenuSelect = () => {
  85. this.setState({show: false})
  86. }
  87. render () {
  88. const {
  89. afterUpdateColor,
  90. currentColor,
  91. nicknameInfo,
  92. reorderingEnabled,
  93. applicationElement,
  94. handleMove,
  95. handleShow,
  96. popoverContentRef,
  97. currentPosition,
  98. lastPosition,
  99. assetString,
  100. menuOptions,
  101. trigger
  102. } = this.props
  103. const colorPicker = (
  104. <div className="DashboardCardMenu__ColorPicker">
  105. <ColorPicker
  106. ref = {(c) => { this._colorPicker = c }}
  107. assetString={assetString}
  108. afterUpdateColor={afterUpdateColor}
  109. hidePrompt
  110. nonModal
  111. hideOnScroll={false}
  112. withAnimation={false}
  113. withBorder={false}
  114. withBoxShadow={false}
  115. withArrow={false}
  116. currentColor={currentColor}
  117. nicknameInfo={nicknameInfo}
  118. afterClose={this.handleClose}
  119. parentComponent="DashboardCardMenu"
  120. focusOnMount={false}
  121. />
  122. </div>
  123. )
  124. const movementMenu = reorderingEnabled ? (
  125. <DashboardCardMovementMenu
  126. ref={(c) => { this._movementMenu = c }}
  127. cardTitle={nicknameInfo.nickname}
  128. currentPosition={currentPosition}
  129. lastPosition={lastPosition}
  130. assetString={assetString}
  131. menuOptions={menuOptions}
  132. handleMove={handleMove}
  133. onMenuSelect={this.handleMovementMenuSelect}
  134. />
  135. ) : null
  136. const menuStyles = {
  137. width: 190,
  138. height: reorderingEnabled ? 310 : 262,
  139. paddingTop: reorderingEnabled ? 0 : 6
  140. }
  141. return (
  142. <Popover
  143. on="click"
  144. show={this.state.show}
  145. onToggle={this.handleMenuToggle}
  146. shouldContainFocus
  147. shouldReturnFocus
  148. closeButtonLabel={I18n.t('Close')}
  149. closeButtonRef={(c) => { this._closeButton = c }}
  150. applicationElement={applicationElement}
  151. defaultFocusElement={() => reorderingEnabled ? this._colorTab : document.getElementById('NicknameInput')}
  152. onShow={handleShow}
  153. contentRef={popoverContentRef}
  154. >
  155. <PopoverTrigger>
  156. {trigger}
  157. </PopoverTrigger>
  158. <PopoverContent>
  159. <div style={menuStyles}>
  160. {reorderingEnabled ?
  161. <div>
  162. <TabList
  163. ref={(c) => { this._tabList = c }}
  164. padding="none"
  165. variant="minimal"
  166. size="small"
  167. >
  168. <TabPanel
  169. padding="none"
  170. title={I18n.t('Color')}
  171. tabRef={(c) => { this._colorTab = c }}
  172. >
  173. {colorPicker}
  174. </TabPanel>
  175. <TabPanel
  176. padding="none"
  177. title={I18n.t('Move')}
  178. >
  179. {movementMenu}
  180. </TabPanel>
  181. </TabList>
  182. </div>
  183. :
  184. <div className="DashboardCardMenu">
  185. {colorPicker}
  186. </div>
  187. }
  188. </div>
  189. </PopoverContent>
  190. </Popover>
  191. )
  192. }
  193. }