diff --git a/packages/xod-client/src/editor/actions.js b/packages/xod-client/src/editor/actions.js index ff62b644c..b3a6d51c7 100644 --- a/packages/xod-client/src/editor/actions.js +++ b/packages/xod-client/src/editor/actions.js @@ -902,9 +902,9 @@ export const sendTweakPulse = tweakNodeId => (dispatch, getState) => { ); }; -export const showColorPickerWidget = elementId => ({ +export const showColorPickerWidget = widgetId => ({ type: ActionType.SHOW_COLORPICKER_WIDGET, - payload: { elementId }, + payload: { widgetId }, }); export const hideColorPickerWidget = () => ({ diff --git a/packages/xod-client/src/editor/components/ColorPicker/SatLightBox.jsx b/packages/xod-client/src/editor/components/ColorPicker/SatLightBox.jsx index c7b4af4e5..835adf650 100644 --- a/packages/xod-client/src/editor/components/ColorPicker/SatLightBox.jsx +++ b/packages/xod-client/src/editor/components/ColorPicker/SatLightBox.jsx @@ -42,16 +42,16 @@ class SatLightBox extends React.Component { this.unbindHandlers = this.unbindHandlers.bind(this); } unbindHandlers() { - document.addEventListener('mousemove', this.handleMove); - document.addEventListener('mouseup', this.handleEnd); - document.addEventListener('dragstart', preventDefaultOnly); + document.removeEventListener('mousemove', this.handleMove); + document.removeEventListener('mouseup', this.handleEnd); + document.removeEventListener('dragstart', preventDefaultOnly); } handleStart() { this.setState({ dragging: true }); document.addEventListener('mousemove', this.handleMove); document.addEventListener('mouseup', this.handleEnd); - document.removeEventListener('dragstart', preventDefaultOnly); + document.addEventListener('dragstart', preventDefaultOnly); } handleMove(event) { diff --git a/packages/xod-client/src/editor/components/ColorPicker/index.jsx b/packages/xod-client/src/editor/components/ColorPicker/index.jsx index d75d04f4b..cf9b03f71 100644 --- a/packages/xod-client/src/editor/components/ColorPicker/index.jsx +++ b/packages/xod-client/src/editor/components/ColorPicker/index.jsx @@ -110,7 +110,7 @@ class ColorPicker extends React.Component {
String +// It makes a safe selector for `querySelector`. +// For example, some variadic inputs have an id, like: +// `#widget_asdasda-$1`, which is not a valid querySelector +// and we have to escap the `$` symbol. +const safeSelector = R.replace(/(\$)/g, '\\$1'); + const getRelativeOffsetTop = (containerEl, el, offset = 0) => { if (el === containerEl) return offset; if (el.tagName === 'BODY') return 0; @@ -88,7 +95,9 @@ class PointingPopup extends React.Component { } onUpdatePosition() { if (!this.ref || !this.props.isVisible) return; - const item = document.querySelector(this.props.selectorPointingAt); + const item = document.querySelector( + safeSelector(this.props.selectorPointingAt) + ); if (!item) return; const container = item.closest('.inner-container'); const position = calculatePointingPopupPosition(container, item); diff --git a/packages/xod-client/src/editor/components/inspectorWidgets/ColorPickerWidget.jsx b/packages/xod-client/src/editor/components/inspectorWidgets/ColorPickerWidget.jsx new file mode 100644 index 000000000..d93e77926 --- /dev/null +++ b/packages/xod-client/src/editor/components/inspectorWidgets/ColorPickerWidget.jsx @@ -0,0 +1,63 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import PointingPopup from '../PointingPopup'; +import ColorPicker from '../ColorPicker'; +import colorPropType from '../ColorPicker/colorPropType'; + +class ColorPickerWidget extends React.Component { + constructor(props) { + super(props); + + this.state = { + color: props.color, + }; + + this.onChange = this.onChange.bind(this); + } + + componentDidUpdate(prevProps) { + if ( + prevProps.color.hex !== this.props.color.hex && + this.state.color.hex !== this.props.color.hex + ) { + // Update the color stored in the state only if it changed + // outside the ColorPicker. + // E.G. user types the new hex color in the input. + // eslint-disable-next-line react/no-did-update-set-state + this.setState({ color: this.props.color }); + } + } + + onChange(color) { + this.setState({ color }); + this.props.onChange(color); + } + + render() { + return ( + + + + ); + } +} + +ColorPickerWidget.propTypes = { + color: colorPropType, + isVisible: PropTypes.bool.isRequired, + widgetId: PropTypes.string, + onChange: PropTypes.func.isRequired, + onClose: PropTypes.func.isRequired, +}; + +export default ColorPickerWidget; diff --git a/packages/xod-client/src/editor/components/inspectorWidgets/pinWidgets/ColorPinWidget.jsx b/packages/xod-client/src/editor/components/inspectorWidgets/pinWidgets/ColorPinWidget.jsx index dab019bad..fcd610ac5 100644 --- a/packages/xod-client/src/editor/components/inspectorWidgets/pinWidgets/ColorPinWidget.jsx +++ b/packages/xod-client/src/editor/components/inspectorWidgets/pinWidgets/ColorPinWidget.jsx @@ -5,17 +5,21 @@ import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import { throttle } from 'throttle-debounce'; -import { showColorPickerWidget, tweakNodeProperty } from '../../../actions'; +import { + showColorPickerWidget, + hideColorPickerWidget, + tweakNodeProperty, +} from '../../../actions'; import PinWidget from './PinWidget'; import { hex2color } from '../../ColorPicker'; -import ColorPickerWidget from '../../../containers/ColorPickerWidget'; +import ColorPickerWidget from '../ColorPickerWidget'; import { isSessionActive } from '../../../../debugger/selectors'; +import { getVisibleColorPickerWidgetId } from '../../../selectors'; class ColorPinWidget extends React.Component { constructor(props) { super(props); this.state = { - value: props.value, focused: false, selection: [0, 0], }; @@ -28,14 +32,10 @@ class ColorPinWidget extends React.Component { this.onWidgetChange = this.onWidgetChange.bind(this); this.onFocus = this.onFocus.bind(this); this.onBlur = this.onBlur.bind(this); - } - componentDidUpdate(prevProps) { - if (prevProps.selection !== this.state.selection && this.inputRef) { - this.inputRef.setSelectionRange( - this.state.selection[0], - this.state.selection[1] - ); - } + + this.showColorPickerWidget = this.showColorPickerWidget.bind(this); + this.hideColorPickerWidget = this.hideColorPickerWidget.bind(this); + this.storeInputRef = this.storeInputRef.bind(this); } onValueTweaked(value) { @@ -43,7 +43,6 @@ class ColorPinWidget extends React.Component { return tweakColor(entityId, kind, keyName, value); } onChangeHandler(value) { - this.setState({ value }); this.props.onChange(value); if (this.props.isActiveSession) { this.onValueTweaked(value); @@ -69,6 +68,17 @@ class ColorPinWidget extends React.Component { this.props.onBlur(); } + showColorPickerWidget() { + this.props.showColorPickerWidget(this.props.elementId); + } + hideColorPickerWidget() { + this.props.hideColorPickerWidget(); + } + + storeInputRef(el) { + this.inputRef = el; + } + render() { return ( { - this.inputRef = el; - }} + ref={this.storeInputRef} />