1- import PropTypes from 'prop-types' ;
2- import React from 'react' ;
1+ import React , { useRef } from 'react' ;
2+
3+ import { bindActionCreators } from 'redux' ;
4+
5+ import { useSelector , useDispatch } from 'react-redux' ;
36import classNames from 'classnames' ;
47import { Console as ConsoleFeed } from 'console-feed' ;
58import {
@@ -22,132 +25,120 @@ import infoContrastUrl from '../../../images/console-info-contrast.svg?byUrl';
2225import UpArrowIcon from '../../../images/up-arrow.svg' ;
2326import DownArrowIcon from '../../../images/down-arrow.svg' ;
2427
25- class Console extends React . Component {
26- componentDidUpdate ( prevProps ) {
27- this . consoleMessages . scrollTop = this . consoleMessages . scrollHeight ;
28- if ( this . props . theme !== prevProps . theme ) {
29- this . props . clearConsole ( ) ;
30- this . props . dispatchConsoleEvent ( this . props . consoleEvents ) ;
31- }
28+ import * as IDEActions from '../../IDE/actions/ide' ;
29+ import * as ConsoleActions from '../../IDE/actions/console' ;
30+ import { useDidUpdate } from '../../../utils/custom-hooks' ;
3231
33- if ( this . props . fontSize !== prevProps . fontSize ) {
34- this . props . clearConsole ( ) ;
35- this . props . dispatchConsoleEvent ( this . props . consoleEvents ) ;
36- }
32+ const getConsoleFeedStyle = ( theme , times , fontSize ) => {
33+ const style = { } ;
34+ const CONSOLE_FEED_LIGHT_ICONS = {
35+ LOG_WARN_ICON : `url(${ warnLightUrl } )` ,
36+ LOG_ERROR_ICON : `url(${ errorLightUrl } )` ,
37+ LOG_DEBUG_ICON : `url(${ debugLightUrl } )` ,
38+ LOG_INFO_ICON : `url(${ infoLightUrl } )`
39+ } ;
40+ const CONSOLE_FEED_DARK_ICONS = {
41+ LOG_WARN_ICON : `url(${ warnDarkUrl } )` ,
42+ LOG_ERROR_ICON : `url(${ errorDarkUrl } )` ,
43+ LOG_DEBUG_ICON : `url(${ debugDarkUrl } )` ,
44+ LOG_INFO_ICON : `url(${ infoDarkUrl } )`
45+ } ;
46+ const CONSOLE_FEED_CONTRAST_ICONS = {
47+ LOG_WARN_ICON : `url(${ warnContrastUrl } )` ,
48+ LOG_ERROR_ICON : `url(${ errorContrastUrl } )` ,
49+ LOG_DEBUG_ICON : `url(${ debugContrastUrl } )` ,
50+ LOG_INFO_ICON : `url(${ infoContrastUrl } )`
51+ } ;
52+ const CONSOLE_FEED_SIZES = {
53+ TREENODE_LINE_HEIGHT : 1.2 ,
54+ BASE_FONT_SIZE : fontSize ,
55+ ARROW_FONT_SIZE : fontSize ,
56+ LOG_ICON_WIDTH : fontSize ,
57+ LOG_ICON_HEIGHT : 1.45 * fontSize ,
58+ } ;
59+
60+ if ( times > 1 ) {
61+ Object . assign ( style , CONSOLE_FEED_WITHOUT_ICONS ) ;
62+ }
63+ switch ( theme ) {
64+ case 'light' :
65+ return Object . assign ( CONSOLE_FEED_LIGHT_STYLES , CONSOLE_FEED_LIGHT_ICONS , CONSOLE_FEED_SIZES , style ) ;
66+ case 'dark' :
67+ return Object . assign ( CONSOLE_FEED_DARK_STYLES , CONSOLE_FEED_DARK_ICONS , CONSOLE_FEED_SIZES , style ) ;
68+ case 'contrast' :
69+ return Object . assign ( CONSOLE_FEED_CONTRAST_STYLES , CONSOLE_FEED_CONTRAST_ICONS , CONSOLE_FEED_SIZES , style ) ;
70+ default :
71+ return '' ;
3772 }
73+ } ;
3874
39- getConsoleFeedStyle ( theme , times ) {
40- const style = { } ;
41- const CONSOLE_FEED_LIGHT_ICONS = {
42- LOG_WARN_ICON : `url(${ warnLightUrl } )` ,
43- LOG_ERROR_ICON : `url(${ errorLightUrl } )` ,
44- LOG_DEBUG_ICON : `url(${ debugLightUrl } )` ,
45- LOG_INFO_ICON : `url(${ infoLightUrl } )`
46- } ;
47- const CONSOLE_FEED_DARK_ICONS = {
48- LOG_WARN_ICON : `url(${ warnDarkUrl } )` ,
49- LOG_ERROR_ICON : `url(${ errorDarkUrl } )` ,
50- LOG_DEBUG_ICON : `url(${ debugDarkUrl } )` ,
51- LOG_INFO_ICON : `url(${ infoDarkUrl } )`
52- } ;
53- const CONSOLE_FEED_CONTRAST_ICONS = {
54- LOG_WARN_ICON : `url(${ warnContrastUrl } )` ,
55- LOG_ERROR_ICON : `url(${ errorContrastUrl } )` ,
56- LOG_DEBUG_ICON : `url(${ debugContrastUrl } )` ,
57- LOG_INFO_ICON : `url(${ infoContrastUrl } )`
58- } ;
59- const CONSOLE_FEED_SIZES = {
60- TREENODE_LINE_HEIGHT : 1.2 ,
61- BASE_FONT_SIZE : this . props . fontSize ,
62- ARROW_FONT_SIZE : this . props . fontSize ,
63- LOG_ICON_WIDTH : this . props . fontSize ,
64- LOG_ICON_HEIGHT : 1.45 * this . props . fontSize ,
65- } ;
75+ const Console = ( ) => {
76+ const consoleEvents = useSelector ( state => state . console ) ;
77+ const isExpanded = useSelector ( state => state . ide . consoleIsExpanded ) ;
78+ const { theme, fontSize } = useSelector ( state => state . preferences ) ;
6679
67- if ( times > 1 ) {
68- Object . assign ( style , CONSOLE_FEED_WITHOUT_ICONS ) ;
69- }
70- switch ( theme ) {
71- case 'light' :
72- return Object . assign ( CONSOLE_FEED_LIGHT_STYLES , CONSOLE_FEED_LIGHT_ICONS , CONSOLE_FEED_SIZES , style ) ;
73- case 'dark' :
74- return Object . assign ( CONSOLE_FEED_DARK_STYLES , CONSOLE_FEED_DARK_ICONS , CONSOLE_FEED_SIZES , style ) ;
75- case 'contrast' :
76- return Object . assign ( CONSOLE_FEED_CONTRAST_STYLES , CONSOLE_FEED_CONTRAST_ICONS , CONSOLE_FEED_SIZES , style ) ;
77- default :
78- return '' ;
79- }
80- }
80+ const {
81+ collapseConsole, expandConsole, clearConsole, dispatchConsoleEvent
82+ } = bindActionCreators ( { ...IDEActions , ...ConsoleActions } , useDispatch ( ) ) ;
8183
82- render ( ) {
83- const consoleClass = classNames ( {
84- 'preview-console' : true ,
85- 'preview-console--collapsed' : ! this . props . isExpanded
86- } ) ;
84+ useDidUpdate ( ( ) => {
85+ clearConsole ( ) ;
86+ dispatchConsoleEvent ( consoleEvents ) ;
87+ } , [ theme , fontSize ] ) ;
8788
88- return (
89- < section className = { consoleClass } >
90- < header className = "preview-console__header" >
91- < h2 className = "preview-console__header-title" > Console</ h2 >
92- < div className = "preview-console__header-buttons" >
93- < button className = "preview-console__clear" onClick = { this . props . clearConsole } aria-label = "Clear console" >
94- Clear
95- </ button >
96- < button
97- className = "preview-console__collapse"
98- onClick = { this . props . collapseConsole }
99- aria-label = "Close console"
100- >
101- < DownArrowIcon focusable = "false" aria-hidden = "true" />
102- </ button >
103- < button className = "preview-console__expand" onClick = { this . props . expandConsole } aria-label = "Open console" >
104- < UpArrowIcon focusable = "false" aria-hidden = "true" />
105- </ button >
106- </ div >
107- </ header >
108- < div ref = { ( element ) => { this . consoleMessages = element ; } } className = "preview-console__messages" >
109- { this . props . consoleEvents . map ( ( consoleEvent ) => {
110- const { method, times } = consoleEvent ;
111- const { theme } = this . props ;
112- return (
113- < div key = { consoleEvent . id } className = { `preview-console__message preview-console__message--${ method } ` } >
114- { times > 1 &&
115- < div
116- className = "preview-console__logged-times"
117- style = { { fontSize : this . props . fontSize , borderRadius : this . props . fontSize / 2 } }
118- >
119- { times }
120- </ div >
121- }
122- < ConsoleFeed
123- styles = { this . getConsoleFeedStyle ( theme , times ) }
124- logs = { [ consoleEvent ] }
125- />
126- </ div >
127- ) ;
128- } ) }
129- </ div >
130- </ section >
131- ) ;
132- }
133- }
89+ const cm = useRef ( { } ) ;
13490
135- Console . propTypes = {
136- consoleEvents : PropTypes . arrayOf ( PropTypes . shape ( {
137- method : PropTypes . string . isRequired ,
138- args : PropTypes . arrayOf ( PropTypes . string )
139- } ) ) ,
140- isExpanded : PropTypes . bool . isRequired ,
141- collapseConsole : PropTypes . func . isRequired ,
142- expandConsole : PropTypes . func . isRequired ,
143- clearConsole : PropTypes . func . isRequired ,
144- dispatchConsoleEvent : PropTypes . func . isRequired ,
145- theme : PropTypes . string . isRequired ,
146- fontSize : PropTypes . number . isRequired
147- } ;
91+ useDidUpdate ( ( ) => { cm . current . scrollTop = cm . current . scrollHeight ; } ) ;
92+
93+ const consoleClass = classNames ( {
94+ 'preview-console' : true ,
95+ 'preview-console--collapsed' : ! isExpanded
96+ } ) ;
14897
149- Console . defaultProps = {
150- consoleEvents : [ ]
98+ return (
99+ < section className = { consoleClass } >
100+ < header className = "preview-console__header" >
101+ < h2 className = "preview-console__header-title" > Console</ h2 >
102+ < div className = "preview-console__header-buttons" >
103+ < button className = "preview-console__clear" onClick = { clearConsole } aria-label = "Clear console" >
104+ Clear
105+ </ button >
106+ < button
107+ className = "preview-console__collapse"
108+ onClick = { collapseConsole }
109+ aria-label = "Close console"
110+ >
111+ < DownArrowIcon focusable = "false" aria-hidden = "true" />
112+ </ button >
113+ < button className = "preview-console__expand" onClick = { expandConsole } aria-label = "Open console" >
114+ < UpArrowIcon focusable = "false" aria-hidden = "true" />
115+ </ button >
116+ </ div >
117+ </ header >
118+ < div ref = { cm } className = "preview-console__messages" >
119+ { consoleEvents . map ( ( consoleEvent ) => {
120+ const { method, times } = consoleEvent ;
121+ return (
122+ < div key = { consoleEvent . id } className = { `preview-console__message preview-console__message--${ method } ` } >
123+ { times > 1 &&
124+ < div
125+ className = "preview-console__logged-times"
126+ style = { { fontSize, borderRadius : fontSize / 2 } }
127+ >
128+ { times }
129+ </ div >
130+ }
131+ < ConsoleFeed
132+ styles = { getConsoleFeedStyle ( theme , times , fontSize ) }
133+ logs = { [ consoleEvent ] }
134+ />
135+ </ div >
136+ ) ;
137+ } ) }
138+ </ div >
139+ </ section >
140+ ) ;
151141} ;
152142
143+
153144export default Console ;
0 commit comments