CollapsibleSection.jsx (5158B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 import { ErrorBoundary } from "content-src/components/ErrorBoundary/ErrorBoundary"; 6 import { FluentOrText } from "content-src/components/FluentOrText/FluentOrText"; 7 import React from "react"; 8 import { connect } from "react-redux"; 9 import { actionCreators as ac, actionTypes as at } from "common/Actions.mjs"; 10 11 /** 12 * A section that can collapse. As of bug 1710937, it can no longer collapse. 13 * See bug 1727365 for follow-up work to simplify this component. 14 */ 15 export class _CollapsibleSection extends React.PureComponent { 16 constructor(props) { 17 super(props); 18 this.onBodyMount = this.onBodyMount.bind(this); 19 this.onMenuButtonMouseEnter = this.onMenuButtonMouseEnter.bind(this); 20 this.onMenuButtonMouseLeave = this.onMenuButtonMouseLeave.bind(this); 21 this.onMenuUpdate = this.onMenuUpdate.bind(this); 22 this.setContextMenuButtonRef = this.setContextMenuButtonRef.bind(this); 23 this.handleTopicSelectionButtonClick = 24 this.handleTopicSelectionButtonClick.bind(this); 25 this.state = { 26 menuButtonHover: false, 27 showContextMenu: false, 28 }; 29 } 30 31 setContextMenuButtonRef(element) { 32 this.contextMenuButtonRef = element; 33 } 34 35 onBodyMount(node) { 36 this.sectionBody = node; 37 } 38 39 onMenuButtonMouseEnter() { 40 this.setState({ menuButtonHover: true }); 41 } 42 43 onMenuButtonMouseLeave() { 44 this.setState({ menuButtonHover: false }); 45 } 46 47 onMenuUpdate(showContextMenu) { 48 this.setState({ showContextMenu }); 49 } 50 51 handleTopicSelectionButtonClick() { 52 const maybeDisplay = 53 this.props.Prefs.values[ 54 "discoverystream.topicSelection.onboarding.maybeDisplay" 55 ]; 56 57 this.props.dispatch(ac.OnlyToMain({ type: at.TOPIC_SELECTION_USER_OPEN })); 58 59 if (maybeDisplay) { 60 // if still part of onboarding, remove user from onboarding flow 61 this.props.dispatch( 62 ac.SetPref( 63 "discoverystream.topicSelection.onboarding.maybeDisplay", 64 false 65 ) 66 ); 67 } 68 this.props.dispatch( 69 ac.BroadcastToContent({ type: at.TOPIC_SELECTION_SPOTLIGHT_OPEN }) 70 ); 71 } 72 73 render() { 74 const { isAnimating, maxHeight, menuButtonHover, showContextMenu } = 75 this.state; 76 const { 77 id, 78 collapsed, 79 title, 80 subTitle, 81 mayHaveTopicsSelection, 82 sectionsEnabled, 83 } = this.props; 84 const active = menuButtonHover || showContextMenu; 85 let bodyStyle; 86 if (isAnimating && !collapsed) { 87 bodyStyle = { maxHeight }; 88 } else if (!isAnimating && collapsed) { 89 bodyStyle = { display: "none" }; 90 } 91 let titleStyle; 92 if (this.props.hideTitle) { 93 titleStyle = { visibility: "hidden" }; 94 } 95 const hasSubtitleClassName = subTitle ? `has-subtitle` : ``; 96 const hasBeenUpdatedPreviously = 97 this.props.Prefs.values[ 98 "discoverystream.topicSelection.hasBeenUpdatedPreviously" 99 ]; 100 const selectedTopics = 101 this.props.Prefs.values["discoverystream.topicSelection.selectedTopics"]; 102 const topicsHaveBeenPreviouslySet = 103 hasBeenUpdatedPreviously || selectedTopics; 104 return ( 105 <section 106 className={`collapsible-section ${this.props.className}${ 107 active ? " active" : "" 108 }`} 109 // Note: data-section-id is used for web extension api tests in mozilla central 110 data-section-id={id} 111 > 112 {!sectionsEnabled && ( 113 <div className="section-top-bar"> 114 <h2 115 className={`section-title-container ${hasSubtitleClassName}`} 116 style={titleStyle} 117 > 118 <span className="section-title"> 119 <FluentOrText message={title} /> 120 </span> 121 {subTitle && ( 122 <span className="section-sub-title"> 123 <FluentOrText message={subTitle} /> 124 </span> 125 )} 126 </h2> 127 {mayHaveTopicsSelection && ( 128 <div className="button-topic-selection"> 129 <moz-button 130 data-l10n-id={ 131 topicsHaveBeenPreviouslySet 132 ? "newtab-topic-selection-button-update-interests" 133 : "newtab-topic-selection-button-pick-interests" 134 } 135 type={topicsHaveBeenPreviouslySet ? "default" : "primary"} 136 onClick={this.handleTopicSelectionButtonClick} 137 /> 138 </div> 139 )} 140 </div> 141 )} 142 <ErrorBoundary className="section-body-fallback"> 143 <div ref={this.onBodyMount} style={bodyStyle}> 144 {this.props.children} 145 </div> 146 </ErrorBoundary> 147 </section> 148 ); 149 } 150 } 151 152 _CollapsibleSection.defaultProps = { 153 document: globalThis.document || { 154 addEventListener: () => {}, 155 removeEventListener: () => {}, 156 visibilityState: "hidden", 157 }, 158 }; 159 160 export const CollapsibleSection = connect(state => ({ 161 Prefs: state.Prefs, 162 }))(_CollapsibleSection);