1+ import React , { useEffect , useState } from 'react' ;
2+ import PropTypes from 'prop-types' ;
3+
14/**
2- * This file contains React component for Panel
5+ * Panel - a collapsible panel component with optional multiple views.
36 *
47 * @author Alex I.
5- * @version 1.0.0
8+ * @version 2.0.0
9+ * @param {object } props
10+ * @return {JSX.Element }
611 */
12+ const Panel = ( props ) => {
13+ const [ collapsed , setCollapsed ] = useState ( false ) ;
14+ const [ activeView , setActiveView ] = useState ( 0 ) ;
715
8- import React , { Component } from 'react' ;
9- import PropTypes from 'prop-types' ;
10-
11- /**
12- * Panel component
13- * Wraps children in a collapsible bootstrap panel
14- */
15- class Panel extends Component {
1616 /**
17- * @constructor
18- * @param {object } props - React Component properties
17+ * Similar to componentDidMount and componentDidUpdate.
1918 */
20- constructor ( props ) {
21- super ( props ) ;
22-
23- this . state = {
24- collapsed : this . props . initCollapsed ,
25- } ;
26-
27- // Initialize panel class based on collapsed status
28- this . panelClass = (
29- this . props . initCollapsed ?
30- 'panel-collapse collapse' :
31- 'panel-collapse collapse in'
32- ) ;
33-
34- this . toggleCollapsed = this . toggleCollapsed . bind ( this ) ;
35- }
19+ useEffect ( ( ) => {
20+ setCollapsed ( props . initCollapsed ) ;
21+ } , [ ] ) ;
3622
3723 /**
38- * Toggle whether this Panel is displayed as collapsed
24+ * Toggle whether panel is displayed as collapsed
3925 */
40- toggleCollapsed ( ) {
41- if ( this . props . collapsing ) {
42- this . setState ( { collapsed : ! this . state . collapsed } ) ;
26+ const toggleCollapsed = ( ) => {
27+ if ( props . collapsing ) {
28+ setCollapsed ( ! collapsed ) ;
4329 }
44- }
30+ } ;
4531
4632 /**
47- * Render the React component
33+ * User clicked a view to display.
4834 *
49- * @return { object }
35+ * @param { number } index
5036 */
51- render ( ) {
52- // Change arrow direction based on collapse status
53- let glyphClass = (
54- this . state . collapsed ?
55- 'glyphicon pull-right glyphicon-chevron-down' :
56- 'glyphicon pull-right glyphicon-chevron-up'
57- ) ;
37+ const viewClicked = ( index ) => {
38+ setActiveView ( index ) ;
39+ } ;
5840
59- const title = this . props . bold ? (
60- < h3 className = { 'panel-title' } >
61- { this . props . title }
62- </ h3 >
63- ) : this . props . title ;
64-
65- // Add panel header, if title is set
66- const panelHeading = this . props . title ? (
67- < div
68- className = "panel-heading"
69- onClick = { this . toggleCollapsed }
70- data-toggle = { this . props . collapsing ? 'collapse' : null }
71- data-target = { '#' + this . props . id }
72- data-parent = { this . props . parentId ?
73- '#' + this . props . parentId :
74- false
75- }
76- style = { {
77- cursor : this . props . collapsing ? 'pointer' : 'default' ,
78- height : '3em' ,
79- fontWeight : 'bold' ,
80- } }
81- >
82- { title }
83- { this . props . collapsing ? < span className = { glyphClass } /> : '' }
84- </ div >
85- ) : '' ;
86-
87- return (
88- < div className = { 'panel ' + this . props . class }
89- style = { { height : this . props . panelSize } }
90- >
91- { panelHeading }
92- < div id = { this . props . id }
93- className = { this . panelClass }
94- role = 'tabpanel'
95- style = { this . props . collapsing ? { } : { height : 'calc(100% - 3em)' } }
96- >
97- < div className = "panel-body"
98- style = { { ...this . props . style , height : this . props . height } } >
99- { this . props . children }
100- </ div >
41+ // Panel Views (START)
42+ let views = [ ] ;
43+ let content = [ ] ;
44+ let panelViews ;
45+ if ( props . views ) {
46+ for ( const [ index , view ] of props . views . entries ( ) ) {
47+ views . push (
48+ < li key = { index }
49+ onClick = { ( ) => viewClicked ( index ) }
50+ className = { index === activeView ? 'active' : null } >
51+ < a data-target = { `${ index } _panel_content` } >
52+ { view [ 'title' ] }
53+ </ a >
54+ </ li >
55+ ) ;
56+ content . push (
57+ < div key = { index }
58+ id = { `${ index } _panel_content_${ props . id } ` }
59+ className = { index === activeView ?
60+ `${ index } _panel_content` : `${ index } _panel_content hidden` } >
61+ { view [ 'content' ] }
10162 </ div >
63+ ) ;
64+ }
65+ panelViews = (
66+ < div className = 'btn-group views' >
67+ < button type = 'button'
68+ className = 'btn btn-default btn-xs dropdown-toggle'
69+ data-toggle = 'dropdown' >
70+ Views< span className = 'caret' />
71+ </ button >
72+ < ul className = 'dropdown-menu pull-right'
73+ role = 'menu' >
74+ { views }
75+ </ ul >
10276 </ div >
10377 ) ;
10478 }
105- }
79+ // Panel Views (END)
10680
81+ // Add panel header, if title is set
82+ const panelHeading = props . title || props . views ? (
83+ < div className = 'panel-heading'
84+ data-parent = { props . parentId
85+ ? `#${ props . parentId } `
86+ : null } >
87+ < h3 className = 'panel-title' >
88+ { props . views && props . views [ activeView ] [ 'title' ]
89+ ? props . views [ activeView ] [ 'title' ]
90+ : props . title }
91+ </ h3 >
92+ { panelViews }
93+ { props . collapsing
94+ ? < span className = { collapsed ?
95+ 'glyphicon glyphicon-chevron-down' :
96+ 'glyphicon glyphicon-chevron-up' }
97+ onClick = { toggleCollapsed }
98+ data-toggle = 'collapse'
99+ data-target = { `#${ props . id } ` }
100+ style = { { cursor : 'pointer' } } />
101+ : null }
102+ </ div >
103+ ) : '' ;
104+
105+ /**
106+ * Renders the React component.
107+ *
108+ * @return {JSX.Element } - React markup for component.
109+ */
110+ return (
111+ < div className = { `panel ${ props . class } ` }
112+ style = { { height : props . panelSize } } >
113+ { panelHeading }
114+ < div id = { props . id }
115+ className = { props . collapsed ?
116+ 'panel-collapse collapse' :
117+ 'panel-collapse collapse in' }
118+ role = 'tabpanel'
119+ style = { { height : 'calc(100% - 3em)' } } >
120+ < div className = 'panel-body'
121+ style = { { ...props . style , height : props . height } } >
122+ { content . length > 0 ? content : props . children }
123+ </ div >
124+ </ div >
125+ </ div >
126+ ) ;
127+ } ;
107128Panel . propTypes = {
108129 initCollapsed : PropTypes . bool ,
130+ collapsed : PropTypes . bool ,
109131 parentId : PropTypes . string ,
110132 id : PropTypes . string ,
111133 height : PropTypes . string ,
112134 title : PropTypes . string ,
113135 class : PropTypes . string ,
136+ children : PropTypes . node ,
137+ views : PropTypes . array ,
114138 collapsing : PropTypes . bool ,
115139 bold : PropTypes . bool ,
116140 panelSize : PropTypes . string ,
@@ -124,8 +148,6 @@ Panel.defaultProps = {
124148 height : '100%' ,
125149 class : 'panel-primary' ,
126150 collapsing : true ,
127- bold : false ,
128- title : '' ,
129151} ;
130152
131153export default Panel ;
0 commit comments