diff --git a/src/jsoneditor/components/jsoneditor.scss b/src/jsoneditor/components/jsoneditor.scss index e67243a..335d907 100644 --- a/src/jsoneditor/components/jsoneditor.scss +++ b/src/jsoneditor/components/jsoneditor.scss @@ -290,71 +290,6 @@ div.jsoneditor-menu-panel-right { max-width: 100%; } -/******************************* Action Menu **********************************/ - -div.jsoneditor-actionmenu { - position: absolute; - box-sizing: border-box; - z-index: 99999; - top: 20px; - left: 18px; /* 20px - 2px where 2px half the difference between 24x24 icons of the menu and the 20x20 icons of the editor */ - background: white; - - border: 1px solid #d3d3d3; - box-shadow: 2px 2px 12px rgba(128, 128, 128, 0.3); -} - -div.jsoneditor-actionmenu.jsoneditor-actionmenu-top { - top: auto; - bottom: 20px; -} - -div.jsoneditor-modemenu.jsoneditor-modemenu { - top: 26px; - left: 0; -} - -div.jsoneditor-menu-item { - line-height: 0; - font-size: 0; -} - -button.jsoneditor-menu-button { - width: 136px; - height: 24px; - padding: 0; - margin: 0; - line-height: 24px; - - background: transparent; - border: transparent; - display: inline-block; - box-sizing: border-box; - - cursor: pointer; - color: #4d4d4d; - - font-size: 10pt; - font-family: arial, sans-serif; - text-align: left; -} - -button.jsoneditor-menu-button:hover, -button.jsoneditor-menu-button:focus { - color: $black; - background-color: #f5f5f5; - outline: none; -} - -button.jsoneditor-menu-button.jsoneditor-selected { - color: white; - background-color: #ee422e; -} - -button.jsoneditor-menu-default { - width: 104px; /* 136px - 32px */ -} - /******************************* Floating Menu **********************************/ div.jsoneditor-node-container { @@ -504,30 +439,6 @@ div.jsoneditor-node-container { /******************************* **********************************/ -div.jsoneditor-modes { - position: relative; - display: inline-block; - - button { - background: none; - width: auto; - padding: 2px 6px; - font-size: $fontSize; - } - - button.jsoneditor-type-modes { - width: 120px; - height: auto; - padding: 2px 6px; - border-radius: 0; - opacity: 1; - - &:hover { - border: none; - } - } -} - textarea.jsoneditor-text { width: 100%; height: 100%; diff --git a/src/jsoneditor/components/menu/ModeDropDown.js b/src/jsoneditor/components/menu/DropDown.js similarity index 64% rename from src/jsoneditor/components/menu/ModeDropDown.js rename to src/jsoneditor/components/menu/DropDown.js index c42787e..ce5cec1 100644 --- a/src/jsoneditor/components/menu/ModeDropDown.js +++ b/src/jsoneditor/components/menu/DropDown.js @@ -1,18 +1,28 @@ -import { createElement as h, Component } from 'react' +import { Component, createElement as h } from 'react' import { toCapital } from '../../utils/stringUtils' import fontawesome from '@fortawesome/fontawesome' import faChevronDown from '@fortawesome/fontawesome-free-solid/faChevronDown' import { keyComboFromEvent } from '../../utils/keyBindings' +import PropTypes from 'prop-types' -import './Menu.css' +import './DropDown.css' fontawesome.library.add(faChevronDown) -const MENU_CLASS_NAME = 'jsoneditor-actionmenu' -const MODE_MENU_CLASS_NAME = MENU_CLASS_NAME + ' jsoneditor-modemenu' +export default class DropDown extends Component { + + static propTypes = { + value: PropTypes.string, + options: PropTypes.arrayOf(PropTypes.shape({ + value: PropTypes.string.isRequired, + text: PropTypes.string, + title: PropTypes.string, + })).isRequired, + onChange: PropTypes.func.isRequired, + onError: PropTypes.func + } -export default class ModeDropDown extends Component { constructor (props) { super (props) @@ -29,14 +39,22 @@ export default class ModeDropDown extends Component { * props {{modes: string[], mode: string, onChangeMode: function, onError: function}} */ render () { - return h('div', {className: 'jsoneditor-modes'}, [ + const selected = this.props.options + ? this.props.options.find(option => option.value === this.props.value) + : null + + const selectedText = selected + ? (selected.text || selected.value) + : '' + + return h('div', {className: 'jsoneditor-dropdown'}, [ h('button', { key: 'button', - className: 'current-mode', + className: 'jsoneditor-dropdown-main-button', title: 'Switch mode', onClick: this.handleOpen }, [ - toCapital(this.props.mode) + ' ', + toCapital(selectedText) + ' ', h('i', { key: 'icon', className: 'fa fa-chevron-down' }) ]), @@ -63,28 +81,29 @@ export default class ModeDropDown extends Component { */ renderDropDown () { if (this.state.open) { - const items = this.props.modes.map(mode => { + const items = this.props.options.map(option => { return h('button', { - key: mode, - title: `Switch to ${mode} mode`, - className: 'jsoneditor-menu-button jsoneditor-type-modes' + - ((mode === this.props.mode) ? ' jsoneditor-selected' : ''), + key: option.value, + ref: 'button', + title: option.title || option.text || option.value, + className: 'jsoneditor-menu-item' + + ((option.value === this.props.value) ? ' jsoneditor-menu-item-selected' : ''), onClick: () => { try { this.handleRequestClose() - this.props.onChangeMode(mode) + this.props.onChange(option.value) } catch (err) { this.props.onError(err) } } - }, toCapital(mode)) + }, toCapital(option.text || option.value)) }) return h('div', { key: 'dropdown', - className: MODE_MENU_CLASS_NAME, + className: 'jsoneditor-dropdown-list', ref: 'menu', onKeyDown: this.handleKeyDown }, items) @@ -112,6 +131,11 @@ export default class ModeDropDown extends Component { event.target.nextSibling.focus() } } + + if (combo ==='Escape') { + this.handleRequestClose() + setTimeout(() => this.focusToDropDownButton()) // FIXME: doesn't work + } } addRequestCloseListener () { @@ -141,5 +165,11 @@ export default class ModeDropDown extends Component { } } + focusToDropDownButton() { + if (this.refs.button) { + this.refs.button.focus() + } + } + handleWindowRequestClose = null } diff --git a/src/jsoneditor/components/menu/DropDown.scss b/src/jsoneditor/components/menu/DropDown.scss new file mode 100644 index 0000000..2ec2561 --- /dev/null +++ b/src/jsoneditor/components/menu/DropDown.scss @@ -0,0 +1,60 @@ +@import '../style.scss'; + +.jsoneditor-dropdown { + position: relative; + display: inline-block; + + button.jsoneditor-dropdown-main-button { + background: none; + width: auto; + padding: 2px 6px; + font-size: $fontSize; + font-weight: bold; + } + + div.jsoneditor-dropdown-list { + position: absolute; + box-sizing: border-box; + z-index: 99999; + top: 26px; + left: 0; + background: white; + + border: 1px solid #d3d3d3; + box-shadow: 2px 2px 12px rgba(128, 128, 128, 0.3); + + button.jsoneditor-menu-item { + display: inline-block; + box-sizing: border-box; + width: 120px; + height: auto; + padding: 2px 6px; + margin: 0; + line-height: 24px; + + border-radius: 0; + opacity: 1; + background: transparent; + border: transparent; + color: #4d4d4d; + font-size: 10pt; + font-family: arial, sans-serif; + text-align: left; + + cursor: pointer; + } + + button.jsoneditor-menu-item:hover, + button.jsoneditor-menu-item:focus { + color: $black; + background-color: #f5f5f5; + outline: none; + } + + button.jsoneditor-menu-item.jsoneditor-menu-item-selected { + color: white; + background-color: #ee422e; + } + } + +} diff --git a/src/jsoneditor/components/menu/Menu.scss b/src/jsoneditor/components/menu/Menu.scss index c1efaab..cb4f233 100644 --- a/src/jsoneditor/components/menu/Menu.scss +++ b/src/jsoneditor/components/menu/Menu.scss @@ -1,5 +1,4 @@ @import '../style.scss'; -@import './MenuButton.scss'; .jsoneditor-menu { // TODO: there is also css for this menu in jsoneditor.scss, move this here @@ -13,4 +12,37 @@ .jsoneditor-menu-group { display: inline-block; } + + .jsoneditor-menu-group:not(:first-child) { + border-left: 1px solid rgba(255,255,255, 0.1); + margin-left: 5px; + padding-left: 5px; + } + + button { + width: 26px; + height: 26px; + margin: 2px; + padding: 0; + border-radius: 2px; + border: 1px solid transparent; + background: transparent; + color: white; + opacity: 0.8; + + font-family: arial, sans-serif; + font-size: 16px; + } + + button:hover { + background-color: rgba(255,255,255,0.2); + border: 1px solid rgba(255,255,255,0.4); + } + button:focus, + button:active { + background-color: rgba(255,255,255,0.3); + } + button:disabled { + opacity: 0.5; + } } diff --git a/src/jsoneditor/components/menu/MenuButton.scss b/src/jsoneditor/components/menu/MenuButton.scss deleted file mode 100644 index 7647893..0000000 --- a/src/jsoneditor/components/menu/MenuButton.scss +++ /dev/null @@ -1,40 +0,0 @@ - -.jsoneditor-menu { - - .jsoneditor-menu-group:not(:first-child) { - border-left: 1px solid rgba(255,255,255, 0.1); - margin-left: 5px; - padding-left: 5px; - } - - button { - width: 26px; - height: 26px; - margin: 2px; - padding: 0; - border-radius: 2px; - border: 1px solid transparent; - background: transparent; - color: white; - opacity: 0.8; - - font-family: arial, sans-serif; - font-size: 16px; - - &.current-mode { - font-weight: bold; - } - } - - button:hover { - background-color: rgba(255,255,255,0.2); - border: 1px solid rgba(255,255,255,0.4); - } - button:focus, - button:active { - background-color: rgba(255,255,255,0.3); - } - button:disabled { - opacity: 0.5; - } -} diff --git a/src/jsoneditor/components/menu/TextModeMenu.js b/src/jsoneditor/components/menu/TextModeMenu.js index 235228a..868adf2 100644 --- a/src/jsoneditor/components/menu/TextModeMenu.js +++ b/src/jsoneditor/components/menu/TextModeMenu.js @@ -1,5 +1,5 @@ import { createElement as h, PureComponent } from 'react' -import ModeDropDown from './ModeDropDown' +import DropDown from './DropDown' import PropTypes from 'prop-types' import fontawesome from '@fortawesome/fontawesome' @@ -30,11 +30,11 @@ export default class TreeModeMenu extends PureComponent { if (this.props.modes ) { items = items.concat([ h('div', {className: 'jsoneditor-menu-group', key: 'mode'}, [ - h(ModeDropDown, { + h(DropDown, { key: 'mode', - modes: this.props.modes, - mode: this.props.mode, - onChangeMode: this.props.onChangeMode, + options: this.props.modes.map(mode => ({ value: mode })), + value: this.props.mode, + onChange: this.props.onChangeMode, onError: this.props.onError }) ]) diff --git a/src/jsoneditor/components/menu/TreeModeMenu.js b/src/jsoneditor/components/menu/TreeModeMenu.js index 8ae34a9..0735fb5 100644 --- a/src/jsoneditor/components/menu/TreeModeMenu.js +++ b/src/jsoneditor/components/menu/TreeModeMenu.js @@ -1,5 +1,5 @@ import { createElement as h, PureComponent } from 'react' -import ModeDropDown from './ModeDropDown' +import DropDown from './DropDown' import PropTypes from 'prop-types' import fontawesome from '@fortawesome/fontawesome' @@ -69,11 +69,11 @@ export default class TreeModeMenu extends PureComponent { if (this.props.modes ) { items = items.concat([ h('div', {className: 'jsoneditor-menu-group', key: 'mode'}, [ - h(ModeDropDown, { + h(DropDown, { key: 'mode', - modes: this.props.modes, - mode: this.props.mode, - onChangeMode: this.props.onChangeMode, + options: this.props.modes.map(mode => ({ value: mode })), + value: this.props.mode, + onChange: this.props.onChangeMode, onError: this.props.onError }) ])