Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

react-style-editor

Package Overview
Dependencies
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-style-editor - npm Package Compare versions

Comparing version 0.1.1 to 0.2.0

2

lib/components/Area.js

@@ -53,3 +53,3 @@ "use strict";

// to combat `isInvalid` from upstream
pointerEvents: 'auto' // to combat the general lock imposed by StyleEditor
pointerEvents: 'auto !important' // to combat the general lock imposed by StyleEditor

@@ -56,0 +56,0 @@ }

@@ -145,9 +145,7 @@ "use strict";

content = _this$props2.content,
onTick = _this$props2.onTick,
onEditChange = _this$props2.onEditChange,
onEditEnd = _this$props2.onEditEnd;
onTick = _this$props2.onTick;
var _this$state = this.state,
isEditingContent = _this$state.isEditingContent,
isEditingAfter = _this$state.isEditingAfter;
var isLegit = !!content.match(/^\s*[-a-zA-Z0-9_]*\s*:|[{}()*@;\/\]]/);
var isLegit = !!content.match(/^\s*[-a-zA-Z0-9_]*\s*:|[{}()*@;/\]]/);
return _react.default.createElement("div", {

@@ -154,0 +152,0 @@ className: classes.root,

@@ -75,2 +75,4 @@ "use strict";

// Chrome
textAlign: 'left',
overflow: 'auto',
color: 'black',

@@ -94,6 +96,9 @@ position: 'relative',

},
isEditing: {
pointerEvents: 'none'
isLocked: {
'& *': {
pointerEvents: 'none'
}
}
}); // =====================================================================================================================
});
var hasControlledWarning = false; // =====================================================================================================================
// C O M P O N E N T

@@ -121,7 +126,2 @@ // =====================================================================================================================

_defineProperty(_assertThisInitialized(_this), "state", {
isEditing: false,
hasArea: false
});
_defineProperty(_assertThisInitialized(_this), "currentRules", []);

@@ -133,3 +133,3 @@

_defineProperty(_assertThisInitialized(_this), "previousPropsCSS", void 0);
_defineProperty(_assertThisInitialized(_this), "isControlled", false);

@@ -149,115 +149,109 @@ _defineProperty(_assertThisInitialized(_this), "computeRules", function (css) {

_defineProperty(_assertThisInitialized(_this), "computeRulesFromPayload", function (id, payload) {
var _modify = (0, _modify2.default)(_this.currentRules, id, payload),
freshRules = _modify.freshRules,
freshNode = _modify.freshNode,
parentNode = _modify.parentNode;
_defineProperty(_assertThisInitialized(_this), "onEditBegin", function () {
_this.setState({
isEditing: true
});
});
if (payload[_COMMON.AFTER_BEGIN]) {
// can only be dispatched by AT/RULE
var node = createTemporaryDeclaration(payload[_COMMON.AFTER_BEGIN]);
freshNode.kids.unshift(node);
} else if (payload[_COMMON.BEFORE]) {
// can only be dispatched by AT/RULE and can only create AT/RULE
var _node = createTemporaryRule(payload[_COMMON.BEFORE]);
_defineProperty(_assertThisInitialized(_this), "onEditChange", function (id, payload) {
var onChange = _this.props.onChange;
var siblings = parentNode.kids;
var index = siblings.findIndex(function (item) {
return item.id === id;
});
siblings.splice(index, 0, _node);
} else if (payload[_COMMON.AFTER]) {
// can be dispatched by any type of node
var text = payload[_COMMON.AFTER];
if (onChange) {
var freshBlob = computeBlobFromPayload(_this.currentRules, id, payload);
var _node2;
_this.announceOnChange(freshBlob);
}
});
switch (freshNode.type) {
// freshNode is in fact the anchor node, NOT the node we're about to create
case _COMMON.ATRULE:
if (freshNode.hasBraceBegin && !freshNode.hasBraceEnd) {
text = '}' + text;
} else if (!freshNode.hasSemicolon) {
text = ';' + text;
}
_defineProperty(_assertThisInitialized(_this), "announceOnChange", function (rulesOrBlob) {
var _this$props = _this.props,
onChange = _this$props.onChange,
outputFormats = _this$props.outputFormats;
_node2 = createTemporaryRule(text);
break;
if (onChange) {
var rules = typeof rulesOrBlob === 'string' ? null : rulesOrBlob; // null means lazy initialization
case _COMMON.RULE:
if (!freshNode.hasBraceEnd) {
text = '}' + text;
}
var formats = outputFormats.replace(/\s/g, '').split(',');
var output = [];
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
_node2 = createTemporaryRule(text);
break;
try {
for (var _iterator = formats[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var format = _step.value;
case _COMMON.DECLARATION:
if (!freshNode.hasSemicolon) {
text = ';' + text;
}
switch (format) {
case 'preserved':
if (rules) {
output.push((0, _stringify.default)(rulesOrBlob));
} else {
output.push(rulesOrBlob);
}
_node2 = createTemporaryDeclaration(text);
break;
break;
case _COMMON.COMMENT:
if (!freshNode.hasSlashEnd) {
text = '*/' + text;
}
case 'machine':
if (!rules) {
rules = _this.computeRules(rulesOrBlob);
}
if (parentNode.type === _COMMON.ATRULE) {
_node2 = createTemporaryRule(text);
} else {
_node2 = createTemporaryDeclaration(text);
}
output.push(JSON.parse(JSON.stringify(rules))); // TODO: use something faster
break;
}
break;
var _siblings = parentNode.kids;
case 'pretty':
default:
if (!rules) {
rules = _this.computeRules(rulesOrBlob);
}
var _index = _siblings.findIndex(function (item) {
return item.id === id;
});
output.push((0, _prettify.default)(rules));
break;
}
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
_siblings.splice(_index + 1, 0, _node2);
} else if (payload.value) {
freshNode.hasColon = true;
onChange(output.length > 1 ? output : output[0] || '');
}
var temporaryBlob = (0, _stringify.default)(freshRules); // console.log(temporaryBlob);
return _this.computeRules(temporaryBlob);
});
_defineProperty(_assertThisInitialized(_this), "onEditBegin", function () {
_this.setState({
isEditing: true
});
});
_defineProperty(_assertThisInitialized(_this), "onEditEnd", function (id, payload) {
if (_this.isControlled) {
_this.setState({
isEditing: false
}); // there's no need to do anything else. Our parent already has the payload from the onChange event
_defineProperty(_assertThisInitialized(_this), "onEditChange", function (id, payload) {
var onChange = _this.props.onChange;
if (onChange) {
var freshRules = _this.computeRulesFromPayload(id, payload);
var prettyBlob = (0, _prettify.default)(freshRules);
onChange(prettyBlob);
} else {
// uncontrolled
_this.setState({
isEditing: false,
internalValue: computeBlobFromPayload(_this.currentRules, id, payload)
});
}
});
_defineProperty(_assertThisInitialized(_this), "onEditEnd", function (id, payload) {
_this.currentRules = _this.computeRulesFromPayload(id, payload);
_this.setState({
isEditing: false
});
});
_defineProperty(_assertThisInitialized(_this), "onTick", function (id, desiredTick) {
var freshBlob = desiredTick ? (0, _unignore.default)(_this.currentRules, id) : (0, _ignore.default)(_this.currentRules, id);
_this.currentRules = _this.computeRules(freshBlob);
_this.forceUpdate();
if (_this.isControlled) {
_this.announceOnChange(freshBlob);
} else {
_this.setState({
internalValue: freshBlob
});
}
});

@@ -283,4 +277,3 @@

if (onChange) {
var prettyBlob = (0, _prettify.default)(_this.computeRules(payload.selector));
onChange(prettyBlob);
_this.announceOnChange(payload.selector);
}

@@ -290,11 +283,24 @@ });

_defineProperty(_assertThisInitialized(_this), "onAreaBlur", function (id, payload) {
_this.currentRules = _this.computeRules(payload.selector);
if (_this.isControlled) {
_this.setState({
isEditing: false,
hasArea: false
}); // there's no need to do anything else. Our parent already has the payload from the onChange event
_this.setState({
isEditing: false,
hasArea: false
});
} else {
// uncontrolled
_this.setState({
isEditing: false,
hasArea: false,
internalValue: payload.selector
});
}
});
(0, _stylize.prepareStyling)();
_this.state = {
isEditing: false,
hasArea: false,
internalValue: props.defaultValue
};
return _this;

@@ -310,18 +316,17 @@ }

value: function render() {
var _this$props = this.props,
css = _this$props.css,
other = _objectWithoutProperties(_this$props, ["css"]);
var _this$props2 = this.props,
value = _this$props2.value,
className = _this$props2.className,
readOnly = _this$props2.readOnly,
other = _objectWithoutProperties(_this$props2, ["value", "className", "readOnly"]);
var _this$state = this.state,
isEditing = _this$state.isEditing,
hasArea = _this$state.hasArea;
hasArea = _this$state.hasArea,
internalValue = _this$state.internalValue;
delete other.outputFormats; // not used in render
if (css !== this.previousPropsCSS) {
// our parent changed the css!
this.currentRules = this.computeRules(css);
this.previousPropsCSS = css;
} else {// the local logic already computed the rules
// nothing to do
}
this.isControlled = checkIsControlled(this.props);
var usedValue = this.isControlled ? value : internalValue;
this.currentRules = this.computeRules(usedValue);
var isEmpty = !this.currentRules.length;

@@ -332,3 +337,3 @@ return _react.default.createElement("div", _extends({

}, other, {
className: (0, _cls.default)(classes.root, isEmpty && !hasArea && classes.isEmpty, isEditing && classes.isEditing)
className: (0, _cls.default)(classes.root, isEmpty && !hasArea && classes.isEmpty, (isEditing || readOnly) && classes.isLocked, className)
}), !isEmpty && _react.default.createElement(_Rule.default, {

@@ -351,2 +356,11 @@ selector: 'root',

/**
*
*/
}, {
key: "componentDidMount",
value: function componentDidMount() {
this.announceOnChange(this.currentRules);
}
/**
* Under no circumstances do we allow updates while an edit is on-going.

@@ -366,3 +380,6 @@ * Alas, because of this small restriction, we had to quit using PureComponent and had to duplicate its

if (this.props[key] !== nextProps[key]) {
return true;
if (key !== 'defaultValue') {
// we're ignoring changes to defaultValue
return true;
}
}

@@ -404,2 +421,110 @@ }

var checkIsControlled = function checkIsControlled(props) {
if (props.value !== undefined) {
if (!props.onChange && !props.readOnly && !hasControlledWarning) {
hasControlledWarning = true;
if (window.console && window.console.warn) {
console.warn('You provided a `value` prop to StyleEditor without an `onChange` handler. ' + 'This will render a read-only field. If the StyleEditor should be mutable, use `defaultValue`. ' + 'Otherwise, set either `onChange` or `readOnly`.');
}
}
return true;
} else {
return false;
}
};
/**
*
*/
var computeBlobFromPayload = function computeBlobFromPayload(rules, id, payload) {
var _modify = (0, _modify2.default)(rules, id, payload),
freshRules = _modify.freshRules,
freshNode = _modify.freshNode,
parentNode = _modify.parentNode;
if (payload[_COMMON.AFTER_BEGIN]) {
// can only be dispatched by AT/RULE
var node = createTemporaryDeclaration(payload[_COMMON.AFTER_BEGIN]);
freshNode.kids.unshift(node);
} else if (payload[_COMMON.BEFORE]) {
// can only be dispatched by AT/RULE and can only create AT/RULE
var _node = createTemporaryRule(payload[_COMMON.BEFORE]);
var siblings = parentNode.kids;
var index = siblings.findIndex(function (item) {
return item.id === id;
});
siblings.splice(index, 0, _node);
} else if (payload[_COMMON.AFTER]) {
// can be dispatched by any type of node
var text = payload[_COMMON.AFTER];
var _node2;
switch (freshNode.type) {
// freshNode is in fact the anchor node, NOT the node we're about to create
case _COMMON.ATRULE:
if (freshNode.hasBraceBegin && !freshNode.hasBraceEnd) {
text = '}' + text;
} else if (!freshNode.hasSemicolon) {
text = ';' + text;
}
_node2 = createTemporaryRule(text);
break;
case _COMMON.RULE:
if (!freshNode.hasBraceEnd) {
text = '}' + text;
}
_node2 = createTemporaryRule(text);
break;
case _COMMON.DECLARATION:
if (!freshNode.hasSemicolon) {
text = ';' + text;
}
_node2 = createTemporaryDeclaration(text);
break;
case _COMMON.COMMENT:
if (!freshNode.hasSlashEnd) {
text = '*/' + text;
}
if (parentNode.type === _COMMON.ATRULE) {
_node2 = createTemporaryRule(text);
} else {
_node2 = createTemporaryDeclaration(text);
}
break;
default: // nothing
}
var _siblings = parentNode.kids;
var _index = _siblings.findIndex(function (item) {
return item.id === id;
});
_siblings.splice(_index + 1, 0, _node2);
} else if (payload.value) {
freshNode.hasColon = true;
}
return (0, _stringify.default)(freshRules);
};
/**
*
*/
var createTemporaryDeclaration = function createTemporaryDeclaration(text) {

@@ -446,3 +571,10 @@ if (!text.match(/;\s*$/)) {

StyleEditor.defaultProps = {
outputFormats: 'pretty',
onChange: null,
defaultValue: '',
value: undefined,
readOnly: false
};
var _default = StyleEditor;
exports.default = _default;

@@ -41,2 +41,5 @@ "use strict";

break;
default: // nothing
}

@@ -43,0 +46,0 @@

@@ -85,2 +85,5 @@ "use strict";

break;
default: // nothing
}

@@ -87,0 +90,0 @@ }

@@ -79,2 +79,5 @@ "use strict";

break;
default: // nothing
}

@@ -81,0 +84,0 @@ }

@@ -54,2 +54,5 @@ "use strict";

break;
default: // nothing
}

@@ -56,0 +59,0 @@ }

@@ -18,6 +18,6 @@ "use strict";

var isAppended = false;
var registry = {};
var cssCollection = [];
var style = document.createElement('style');
var count = 0;
/**

@@ -87,6 +87,8 @@ *

var prepareStyling = function prepareStyling() {
if (!isAppended) {
count++;
if (count === 1) {
// TODO: study impact on hot loading
style.innerHTML = cssCollection.join('');
document.head.appendChild(style);
isAppended = true;
}

@@ -102,6 +104,7 @@ };

var releaseStyling = function releaseStyling() {
if (isAppended) {
count--;
if (count === 0) {
document.head.removeChild(style);
style.innerHTML = '';
isAppended = false;
}

@@ -108,0 +111,0 @@ };

{
"name": "react-style-editor",
"version": "0.1.1",
"version": "0.2.0",
"description": "A React component that displays and edits CSS, similar to the browser's DevTools.",

@@ -5,0 +5,0 @@ "main": "lib/index.js",

# React Style Editor
[![Npm Version][npm-version-image]][npm-version-url]   [![License][license-image]][license-url]  
[![Size][bundlephobia-image]][bundlephobia-url]
[![Npm Version][npm-version-image]][npm-version-url]   [![Size][bundlephobia-image]][bundlephobia-url]

@@ -10,2 +9,6 @@

[![Live demo](https://aurelain.github.io/react-style-editor/StyleEditor.png)](https://aurelain.github.io/react-style-editor/)
## [Live demo](https://aurelain.github.io/react-style-editor/)
## Features

@@ -17,7 +20,8 @@ - Parses any CSS string and formats it in a familiar fashion

- Has no dependencies (other than React)
- Is tiny (< 10 KB minified)
- Is customizable through classes
- Offers 3 output formats:
- the code with preserved formatting
- a machine-friendly model of the code (recursive array of objects)
- the prettified code
- a machine-friendly model of the code (recursive array of objects)

@@ -41,3 +45,3 @@ ## Installation

<StyleEditor
css={`
defaultValue={`
div {color:red;}

@@ -57,8 +61,30 @@ /* Hello, World! */

## Props
|prop | type | default |description |
|---------------|------------------------|----------------------------------------------------|--------|
| `defaultValue` | string | `''` | The initial CSS code
| `value` | string | `undefined` | The controlled CSS code
| `onChange` | function | `null` | A closure that receives a single argument, `string` or `array`, depending on the value of `outputFormats`
| `outputFormats` | string | `'pretty'` | Comma-separated values of: `'preserved'`, `'machine'`, `'pretty'`
| `readOnly` | boolean | `false` | All interactions with the component are blocked
All parameters are optional, but some are inter-related. For example, due to the nature of React, you should use `StyleEditor` either fully controlled or fully uncontrolled (see [this article](https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#preferred-solutions)).
A short summary:
- `defaultValue` => uncontrolled, the component is on its own
- `value` => controlled => you must also use the `onChange` or `readOnly` properties.
The above behavior is identical to that of normal React form elements, e.g. `<textarea/>`.
Any other props are spread to the internal root.
## Ideas for the future
- Live demo
- Color swatches (similar to the browser)
- Dropdown suggestions for properties/values (similar to the browser)
- Ability to copy/delete fragments of code
- Keyboard support for `TAB`, `:` and `UP`, `DOWN`
- Keyboard support for `TAB`, `:` and `UP`/`DOWN` increments of numeric values
- Prop for automatically mutating the code *after* validation

@@ -76,6 +102,3 @@ - Theme support (similar to the browser)

[license-image]: http://img.shields.io/npm/l/react-style-editor.svg?style=flat-square
[license-url]: https://github.com/Aurelain/react-style-editor/blob/master/LICENSE
[bundlephobia-image]: https://img.shields.io/bundlephobia/minzip/react-style-editor.svg?style=flat-square
[bundlephobia-url]: https://bundlephobia.com/result?p=react-style-editor

@@ -22,3 +22,3 @@ import React from 'react';

textDecoration: 'none', // to combat `isInvalid` from upstream
pointerEvents: 'auto', // to combat the general lock imposed by StyleEditor
pointerEvents: 'auto !important', // to combat the general lock imposed by StyleEditor
},

@@ -25,0 +25,0 @@ });

@@ -47,6 +47,6 @@ import React from 'react';

render() {
const {id, content, onTick, onEditChange, onEditEnd} = this.props;
const {id, content, onTick} = this.props;
const {isEditingContent, isEditingAfter} = this.state;
const isLegit = !!content.match(/^\s*[-a-zA-Z0-9_]*\s*:|[{}()*@;\/\]]/);
const isLegit = !!content.match(/^\s*[-a-zA-Z0-9_]*\s*:|[{}()*@;/\]]/);

@@ -53,0 +53,0 @@ return (

@@ -24,2 +24,4 @@ import React from 'react';

fontSize: '12px', // Chrome
textAlign: 'left',
overflow: 'auto',
color: 'black',

@@ -43,6 +45,9 @@ position: 'relative',

},
isEditing: {
pointerEvents: 'none',
isLocked: {
'& *': {
pointerEvents: 'none',
}
},
});
let hasControlledWarning = false;

@@ -54,7 +59,2 @@ // =====================================================================================================================

state = {
isEditing: false,
hasArea: false,
};
// Private variables:

@@ -64,3 +64,3 @@ currentRules = [];

memoCSS = ''; // a simulation of `memoize-one`
previousPropsCSS;
isControlled = false;

@@ -73,2 +73,7 @@ /**

prepareStyling();
this.state = {
isEditing: false,
hasArea: false,
internalValue: props.defaultValue,
};
}

@@ -80,11 +85,10 @@

render() {
const {css, ...other} = this.props;
const {isEditing, hasArea} = this.state;
const {value, className, readOnly, ...other} = this.props;
const {isEditing, hasArea, internalValue} = this.state;
delete other.outputFormats; // not used in render
if (css !== this.previousPropsCSS) { // our parent changed the css!
this.currentRules = this.computeRules(css);
this.previousPropsCSS = css;
} else { // the local logic already computed the rules
// nothing to do
}
this.isControlled = checkIsControlled(this.props);
const usedValue = this.isControlled ? value : internalValue;
this.currentRules = this.computeRules(usedValue);
const isEmpty = !this.currentRules.length;

@@ -97,3 +101,8 @@

{...other}
className={cls(classes.root, isEmpty && !hasArea && classes.isEmpty, isEditing && classes.isEditing)}
className={cls(
classes.root,
isEmpty && !hasArea && classes.isEmpty,
(isEditing || readOnly) && classes.isLocked,
className,
)}
>

@@ -127,2 +136,9 @@ {

/**
*
*/
componentDidMount() {
this.announceOnChange(this.currentRules);
}
/**
* Under no circumstances do we allow updates while an edit is on-going.

@@ -138,3 +154,5 @@ * Alas, because of this small restriction, we had to quit using PureComponent and had to duplicate its

if (this.props[key] !== nextProps[key]) {
return true;
if (key !== 'defaultValue') { // we're ignoring changes to defaultValue
return true;
}
}

@@ -175,64 +193,2 @@ }

*/
computeRulesFromPayload = (id, payload) => {
const {freshRules, freshNode, parentNode} = modify(this.currentRules, id, payload);
if (payload[AFTER_BEGIN]) { // can only be dispatched by AT/RULE
const node = createTemporaryDeclaration(payload[AFTER_BEGIN]);
freshNode.kids.unshift(node);
} else if (payload[BEFORE]) { // can only be dispatched by AT/RULE and can only create AT/RULE
const node = createTemporaryRule(payload[BEFORE]);
const siblings = parentNode.kids;
const index = siblings.findIndex(item => item.id === id);
siblings.splice(index, 0, node);
} else if (payload[AFTER]) { // can be dispatched by any type of node
let text = payload[AFTER];
let node;
switch (freshNode.type) { // freshNode is in fact the anchor node, NOT the node we're about to create
case ATRULE:
if (freshNode.hasBraceBegin && !freshNode.hasBraceEnd) {
text = '}' + text;
} else if (!freshNode.hasSemicolon) {
text = ';' + text;
}
node = createTemporaryRule(text);
break;
case RULE:
if (!freshNode.hasBraceEnd) {
text = '}' + text;
}
node = createTemporaryRule(text);
break;
case DECLARATION:
if (!freshNode.hasSemicolon) {
text = ';' + text;
}
node = createTemporaryDeclaration(text);
break;
case COMMENT:
if (!freshNode.hasSlashEnd) {
text = '*/' + text;
}
if (parentNode.type === ATRULE) {
node = createTemporaryRule(text);
} else {
node = createTemporaryDeclaration(text);
}
break;
}
const siblings = parentNode.kids;
const index = siblings.findIndex(item => item.id === id);
siblings.splice(index + 1, 0, node);
} else if (payload.value) {
freshNode.hasColon = true;
}
const temporaryBlob = stringify(freshRules);
// console.log(temporaryBlob);
return this.computeRules(temporaryBlob);
};
/**
*
*/
onEditBegin = () => {

@@ -250,5 +206,4 @@ this.setState({

if (onChange) {
const freshRules = this.computeRulesFromPayload(id, payload);
const prettyBlob = prettify(freshRules);
onChange(prettyBlob);
const freshBlob = computeBlobFromPayload(this.currentRules, id, payload);
this.announceOnChange(freshBlob);
}

@@ -260,7 +215,52 @@ };

*/
announceOnChange = (rulesOrBlob) => {
const {onChange, outputFormats} = this.props;
if (onChange) {
let rules = typeof rulesOrBlob === 'string'? null : rulesOrBlob; // null means lazy initialization
const formats = outputFormats.replace(/\s/g, '').split(',');
const output = [];
for (const format of formats) {
switch (format) {
case 'preserved':
if (rules) {
output.push(stringify(rulesOrBlob));
} else {
output.push(rulesOrBlob);
}
break;
case 'machine':
if (!rules) {
rules = this.computeRules(rulesOrBlob);
}
output.push(JSON.parse(JSON.stringify(rules))); // TODO: use something faster
break;
case 'pretty':
default:
if (!rules) {
rules = this.computeRules(rulesOrBlob);
}
output.push(prettify(rules));
break;
}
}
onChange(output.length > 1 ? output : (output[0] || ''));
}
};
/**
*
*/
onEditEnd = (id, payload) => {
this.currentRules = this.computeRulesFromPayload(id, payload);
this.setState({
isEditing: false,
});
if (this.isControlled) {
this.setState({
isEditing: false,
});
// there's no need to do anything else. Our parent already has the payload from the onChange event
} else { // uncontrolled
this.setState({
isEditing: false,
internalValue: computeBlobFromPayload(this.currentRules, id, payload)
});
}
};

@@ -273,4 +273,9 @@

const freshBlob = desiredTick ? unignore(this.currentRules, id) : ignore(this.currentRules, id);
this.currentRules = this.computeRules(freshBlob);
this.forceUpdate();
if (this.isControlled) {
this.announceOnChange(freshBlob);
} else {
this.setState({
internalValue: freshBlob,
})
}
};

@@ -304,4 +309,3 @@

if (onChange) {
const prettyBlob = prettify(this.computeRules(payload.selector));
onChange(prettyBlob);
this.announceOnChange(payload.selector);
}

@@ -314,7 +318,16 @@ };

onAreaBlur = (id, payload) => {
this.currentRules = this.computeRules(payload.selector);
this.setState({
isEditing: false,
hasArea: false,
});
if (this.isControlled) {
this.setState({
isEditing: false,
hasArea: false,
});
// there's no need to do anything else. Our parent already has the payload from the onChange event
} else { // uncontrolled
this.setState({
isEditing: false,
hasArea: false,
internalValue: payload.selector
});
}
};

@@ -330,2 +343,83 @@

*/
const checkIsControlled = (props) => {
if (props.value !== undefined) {
if (!props.onChange && !props.readOnly && !hasControlledWarning) {
hasControlledWarning = true;
if (window.console && window.console.warn) {
console.warn('You provided a `value` prop to StyleEditor without an `onChange` handler. ' +
'This will render a read-only field. If the StyleEditor should be mutable, use `defaultValue`. ' +
'Otherwise, set either `onChange` or `readOnly`.');
}
}
return true;
} else {
return false;
}
};
/**
*
*/
const computeBlobFromPayload = (rules, id, payload) => {
const {freshRules, freshNode, parentNode} = modify(rules, id, payload);
if (payload[AFTER_BEGIN]) { // can only be dispatched by AT/RULE
const node = createTemporaryDeclaration(payload[AFTER_BEGIN]);
freshNode.kids.unshift(node);
} else if (payload[BEFORE]) { // can only be dispatched by AT/RULE and can only create AT/RULE
const node = createTemporaryRule(payload[BEFORE]);
const siblings = parentNode.kids;
const index = siblings.findIndex(item => item.id === id);
siblings.splice(index, 0, node);
} else if (payload[AFTER]) { // can be dispatched by any type of node
let text = payload[AFTER];
let node;
switch (freshNode.type) { // freshNode is in fact the anchor node, NOT the node we're about to create
case ATRULE:
if (freshNode.hasBraceBegin && !freshNode.hasBraceEnd) {
text = '}' + text;
} else if (!freshNode.hasSemicolon) {
text = ';' + text;
}
node = createTemporaryRule(text);
break;
case RULE:
if (!freshNode.hasBraceEnd) {
text = '}' + text;
}
node = createTemporaryRule(text);
break;
case DECLARATION:
if (!freshNode.hasSemicolon) {
text = ';' + text;
}
node = createTemporaryDeclaration(text);
break;
case COMMENT:
if (!freshNode.hasSlashEnd) {
text = '*/' + text;
}
if (parentNode.type === ATRULE) {
node = createTemporaryRule(text);
} else {
node = createTemporaryDeclaration(text);
}
break;
default:
// nothing
}
const siblings = parentNode.kids;
const index = siblings.findIndex(item => item.id === id);
siblings.splice(index + 1, 0, node);
} else if (payload.value) {
freshNode.hasColon = true;
}
return stringify(freshRules);
};
/**
*
*/
const createTemporaryDeclaration = (text) => {

@@ -364,2 +458,9 @@ if (!text.match(/;\s*$/)) { // doesn't end with semicolon

// =====================================================================================================================
StyleEditor.defaultProps = {
outputFormats: 'pretty',
onChange: null,
defaultValue: '',
value: undefined,
readOnly: false,
};
export default StyleEditor;

@@ -30,2 +30,4 @@ /*

break;
default:
// nothing
}

@@ -32,0 +34,0 @@ if (id in usedIds) {

@@ -69,2 +69,4 @@ /*

break;
default:
// nothing
}

@@ -71,0 +73,0 @@ }

@@ -47,2 +47,4 @@ /*

break;
default:
// nothing
}

@@ -49,0 +51,0 @@ }

@@ -49,2 +49,4 @@ /*

break;
default:
// nothing
}

@@ -51,0 +53,0 @@ }

@@ -9,6 +9,6 @@ /*

let isAppended = false;
let registry = {};
let cssCollection = [];
let style = document.createElement('style');
let count = 0;

@@ -67,6 +67,6 @@

const prepareStyling = () => {
if (!isAppended) {
count++;
if (count === 1) { // TODO: study impact on hot loading
style.innerHTML = cssCollection.join('');
document.head.appendChild(style);
isAppended = true;
}

@@ -79,6 +79,6 @@ };

const releaseStyling = () => {
if (isAppended) {
count--;
if (count === 0) {
document.head.removeChild(style);
style.innerHTML = '';
isAppended = false;
}

@@ -85,0 +85,0 @@ };

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc