New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

react-shadow

Package Overview
Dependencies
Maintainers
1
Versions
84
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-shadow - npm Package Compare versions

Comparing version 1.1.2 to 2.0.0

example/js/actions.js

17

example/server/default.js

@@ -1,8 +0,15 @@

import http from 'http';
import express from 'express';
import { readFileSync } from 'fs';
import http from 'http';
import express from 'express';
const app = express();
const app = express();
const server = http.createServer(app);
const port = process.env.PORT || 5000;
app.use(express.static(__dirname + '/example'));
server.listen(process.env.PORT || 5000);
app.get(/\.html$/i, (_, res) => {
res.send(readFileSync(`${__dirname}/example/index.html`, 'utf-8'));
});
app.use(express.static(`${__dirname}/example`));
server.listen(port);
{
"name": "react-shadow",
"version": "1.1.2",
"version": "2.0.0",
"description": "Utilise Shadow DOM in React with all the benefits of style encapsulation.",
"main": "dist/react-shadow.js",
"scripts": {
"prestart": "npm run build",
"start": "babel example/server/default.js | node",
"build": "webpack && npm run example",
"watch": "webpack --config webpack.dev-config.js --watch",
"example": "webpack --config webpack.dev-config.js",

@@ -32,2 +34,6 @@ "test": "npm run spec && npm run lint",

"homepage": "https://github.com/Wildhoney/ReactShadow",
"dependencies": {
"react": ">=0.14.7 <=15.x",
"react-dom": ">=0.14.7 <=15.x"
},
"devDependencies": {

@@ -40,2 +46,3 @@ "ava": "^0.16.0",

"babel-loader": "^6.2.5",
"babel-polyfill": "~6.23.0",
"babel-preset-es2015": "^6.14.0",

@@ -52,2 +59,3 @@ "babel-preset-react": "^6.11.1",

"express": "^4.11.2",
"humps": "~2.0.0",
"jasmine-core": "^2.2.0",

@@ -58,2 +66,9 @@ "jsdom": "^9.5.0",

"react-addons-test-utils": "^15.3.1",
"react-document-title": "~2.0.3",
"react-redux": "~5.0.3",
"react-router": "~4.0.0",
"react-router-dom": "~4.0.0",
"react-thunk": "~1.0.0",
"redux": "~3.6.0",
"redux-thunk": "~2.2.0",
"sinon": "^1.17.5",

@@ -98,3 +113,5 @@ "webpack": "^2.1.0-beta.22",

],
"key-spacing": "off",
"default-case": "off",
"no-multi-spaces": "off",
"no-unused-expressions": "off",

@@ -117,7 +134,3 @@ "no-case-declarations": "off",

}
},
"dependencies": {
"react": ">=0.14.7 <=15.x",
"react-dom": ">=0.14.7 <=15.x"
}
}

@@ -1,10 +0,25 @@

import { get as fetch } from 'axios';
import { get as fetch } from 'axios';
import React, { Component, PropTypes, DOM, Children } from 'react';
import { render, findDOMNode } from 'react-dom';
import dissoc from 'ramda/src/dissoc';
import memoize from 'ramda/src/memoize';
import groupBy from 'ramda/src/groupBy';
import { render, findDOMNode } from 'react-dom';
import { dissoc, memoize, groupBy } from 'ramda';
/**
* @method raise
* @constant includeMap
* @type {Object}
*/
const includeMap = [
{ extensions: ['js'], tag: 'script', attrs: { type: 'text/javascript' } },
{ extensions: ['css'], tag: 'style', attrs: { type: 'text/css' } }
];
/**
* @constant defaultContextTypes
* @type {Object}
*/
const defaultContextTypes = {
router: PropTypes.object
};
/**
* @method throwError
* @param {String} message

@@ -14,3 +29,3 @@ * @throws {Error}

*/
const raise = message => {
const throwError = message => {
throw new Error(`ReactShadow: ${message}.`);

@@ -33,190 +48,264 @@ };

/**
* @constant includeMap
* @type {Object}
* @method withContext
* @param {Object} contextTypes
* @return {ShadowDOM}
*/
const includeMap = [
{
extensions: ['js'], tag: 'script', attrs: {
type: 'text/javascript'
}
},
{
extensions: ['css'], tag: 'style', attrs: {
type: 'text/css'
}
}
];
export const withContext = contextTypes => {
/**
* @class ShadowDOM
* @extends Component
*/
export default class ShadowDOM extends Component {
/**
* @constant propTypes
* @type {Object}
* @method createContextProvider
* @param {Object} context
* @return {ContextProvider}
*/
static propTypes = {
children: PropTypes.node.isRequired,
include: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
nodeName: PropTypes.string,
boundaryMode: PropTypes.oneOf(['open', 'closed']),
delegatesFocus: PropTypes.bool
};
const createContextProvider = context => {
/**
* @constant defaultProps
* @type {Object}
*/
static defaultProps = {
include: [],
nodeName: 'span',
boundaryMode: 'open',
delegatesFocus: false
/**
* @class ContextProvider
* @extends {Component}
*/
class ContextProvider extends Component {
/**
* @constant propTypes
* @type {Object}
*/
static propTypes = {
children: PropTypes.node.isRequired
};
/**
* @constant childContextTypes
* @type {Object}
*/
static childContextTypes = contextTypes;
/**
* @method shouldComponentUpdate
* @return {Boolean}
*/
shouldComponentUpdate() {
return true;
}
/**
* @method getChildContext
* @return {Object}
*/
getChildContext() {
return context;
}
/**
* @method render
* @return {XML}
*/
render() {
return this.props.children;
}
}
return ContextProvider;
};
/**
* @constructor
* @class ShadowDOM
* @extends Component
*/
constructor() {
super();
this.state = { resolving: false };
}
return class ShadowDOM extends Component {
/**
* @method getContainer
* @return {Object}
*/
getContainer() {
/**
* @constant contextTypes
* @type {Object}
*/
static contextTypes = contextTypes;
// Wrap children in a container if it's an array of children, otherwise
// simply render the single child which is a valid `ReactElement` instance.
const children = this.props.children.props.children;
return children.length ? <this.props.nodeName>{children}</this.props.nodeName> : children;
/**
* @constant propTypes
* @type {Object}
*/
static propTypes = {
children: PropTypes.node.isRequired,
include: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
nodeName: PropTypes.string,
boundaryMode: PropTypes.oneOf(['open', 'closed']),
delegatesFocus: PropTypes.bool
};
}
/**
* @constant defaultProps
* @type {Object}
*/
static defaultProps = {
include: [],
nodeName: 'span',
boundaryMode: 'open',
delegatesFocus: false
};
/**
* @method componentDidMount
* @return {void}
*/
componentDidMount() {
/**
* @constant state
* @type {Object}
*/
state = { resolving: false };
const { boundaryMode: mode, delegatesFocus} = this.props;
/**
* @constant ContextProvider
* @type {ContextProvider}
*/
ContextProvider = createContextProvider(this.context);
// Create the shadow root and take the CSS documents from props.
const node = findDOMNode(this);
const root = node.attachShadow ? node.attachShadow({ mode, delegatesFocus }) : node.createShadowRoot();
const include = Array.isArray(this.props.include) ? this.props.include : [this.props.include];
const container = this.getContainer();
/**
* @constant WrappedComponent
* @type {Object}
*/
WrappedComponent = this.props.children;
// Render the passed in component to the shadow root, and then `setState` if there
// are no CSS documents to be resolved.
render(container, root);
!include.length && this.setState({ root });
/**
* @method componentDidMount
* @return {void}
*/
componentDidMount() {
if (include.length) {
const { boundaryMode: mode, delegatesFocus } = this.props;
// Otherwise we'll fetch and attach the passed in stylesheets which need to be
// resolved before `state.resolved` becomes `true` again.
this.setState({ resolving: true, root });
this.attachIncludes(include);
// Create the shadow root and take the CSS documents from props.
const node = findDOMNode(this);
const root = node.attachShadow ? node.attachShadow({ mode, delegatesFocus }) : node.createShadowRoot();
const include = [].concat(this.props.include);
const container = this.wrapContainer();
// Render the passed in component to the shadow root, and then `setState` if there
// are no CSS documents to be resolved.
render(container, root);
include.length === 0 ? this.setState({ root }) : do {
// Otherwise we'll fetch and attach the passed in stylesheets which need to be
// resolved before `state.resolved` becomes `true` again.
this.setState({ root, resolving: true });
this.attachIncludes(include);
};
}
}
/**
* @method wrapContainer
* @return {Object}
*/
wrapContainer() {
/**
* @method componentDidUpdate
* @return {void}
*/
componentDidUpdate() {
// Wrap children in a container if it's an array of children, otherwise simply render the single child
// which is a valid `ReactElement` instance.
const { children } = this.props.children.props;
const child = children.length ? <this.props.nodeName>{children}</this.props.nodeName> : children;
const ContextProvider = this.ContextProvider;
// Updates consist of simply rendering the container element into the shadow root
// again, as the `this.getContainer()` element contains the passed in component's
// children.
render(this.getContainer(), this.state.root);
/**
* @method getChildContext
* @return {Object}
*/
ContextProvider.prototype.getChildContext = () => this.context;
}
return <ContextProvider>{child}</ContextProvider>;
/**
* @method attachIncludes
* @param include {Array|String}
* @return {void}
*/
attachIncludes(include) {
}
// Group all of the includes by their extension.
const groupedFiles = groupBy(file => file.extension)(include.map(path => ({ path, extension: path.split('.').pop() })));
/**
* @method componentDidUpdate
* @return {void}
*/
componentDidUpdate() {
const includeFiles = Object.keys(groupedFiles).map(extension => {
// Updates consist of simply rendering the container element into the shadow root
// again, as the `this.wrapContainer()` element contains the passed in component's
// children.
render(this.wrapContainer(), this.state.root);
const nodeData = includeMap.find(model => model.extensions.includes(extension));
const files = groupedFiles[extension].map(model => model.path);
}
if (!nodeData) {
raise(`Files with extension of "${extension}" are unsupported`);
}
/**
* @method attachIncludes
* @param include {Array}
* @return {void}
*/
attachIncludes(include) {
const containerElement = document.createElement(nodeData.tag);
// Group all of the includes by their extension.
const groupedFiles = groupBy(file => file.extension)(include.map(path => ({ path, extension: path.split('.').pop() })));
const includeFiles = Object.keys(groupedFiles).map(extension => {
// Apply all of the attributes defined in the `includeMap` to the node.
Object.keys(nodeData.attrs).map(key => containerElement.setAttribute(key, nodeData.attrs[key]));
const nodeData = includeMap.find(model => model.extensions.includes(extension));
const files = groupedFiles[extension].map(model => model.path);
// Load each file individually and then concatenate them.
return Promise.all(files.map(fetchInclude)).then(fileData => {
containerElement.innerHTML = fileData.reduce((acc, fileDatum) => `${acc} ${fileDatum}`).trim();
containerElement.innerHTML.length && this.state.root.appendChild(containerElement);
!nodeData && throwError(`Files with extension of "${extension}" are unsupported`);
const containerElement = document.createElement(nodeData.tag);
// Apply all of the attributes defined in the `includeMap` to the node.
Object.keys(nodeData.attrs).map(key => containerElement.setAttribute(key, nodeData.attrs[key]));
// Load each file individually and then concatenate them.
return Promise.all(files.map(fetchInclude)).then(fileData => {
containerElement.innerHTML = fileData.reduce((acc, fileDatum) => `${acc} ${fileDatum}`).trim();
containerElement.innerHTML.length && this.state.root.appendChild(containerElement);
});
});
});
Promise.all(includeFiles).then(() => this.setState({ resolving: false }));
Promise.all(includeFiles).then(() => this.setState({ resolving: false }));
}
}
/**
* @method throwInvariants
* @return {Boolean|void}
*/
throwInvariants() {
/**
* @method performSanityChecks
* @return {void}
*/
performSanityChecks() {
// Ensure that the passed child isn't an array of children.
Array.isArray(this.props.children) && throwError('You must pass a single child rather than multiple children');
// Ensure that the passed child isn't an array of children.
Array.isArray(this.props.children) && raise('You must pass a single child rather than multiple children');
if (typeof this.props.children.type !== 'string') {
if (typeof this.props.children.type !== 'string') {
// Ensure that the passed child has a valid node name.
throwError('Passed child must be a concrete HTML element rather than another React component');
// Ensure that the passed child has a valid node name.
raise('Passed child must be a concrete HTML element rather than another React component');
}
return true;
}
}
/**
* @method render
* @return {XML}
*/
render() {
/**
* @method render
* @return {XML}
*/
render() {
return this.throwInvariants() && do {
// Process the necessary sanity checks.
this.performSanityChecks();
// Props from the passed component, minus `children` as that's handled by `componentDidMount`.
const child = Children.only(this.props.children);
const childProps = dissoc('children', child.props);
const className = this.state.resolving ? 'resolving' : 'resolved';
// Take all of the props from the passed in component, minus the `children` props
// as that's handled by `componentDidMount`.
const child = Children.only(this.props.children);
const props = dissoc('children', child.props);
const className = this.state.resolving ? 'resolving' : 'resolved';
// See: https://github.com/facebook/react/issues/4933
const classNames = `${childProps.className ? childProps.className : ''} ${className}`.trim();
const isSupported = child.type in DOM;
const classProp = isSupported ? 'className' : 'class';
const props = { ...dissoc('className', childProps), [classProp]: classNames };
// Determine whether to use `class` or `className`, as custom elements do not allow
// for `className`. See: https://github.com/facebook/react/issues/4933
const classNames = `${props.className ? props.className : ''} ${className}`.trim();
const isSupportedElement = child.type in DOM;
const propName = isSupportedElement ? 'className' : 'class';
<child.type {...props} />;
return <child.type {...{ ...dissoc('className', props), [propName]: classNames }} />;
};
}
}
}
};
};
export default withContext(defaultContextTypes);

@@ -55,3 +55,3 @@ import test from 'ava';

t.is(attachShadow.callCount, 1);
t.true(attachShadow.calledWith({ mode: 'open' }));
t.true(attachShadow.calledWith({ mode: 'open', delegatesFocus: false }));

@@ -75,6 +75,15 @@ const host = wrapper.find('section');

mount(<Clock />);
t.true(attachShadow.calledWith({ mode: 'closed' }));
t.true(attachShadow.calledWith({ mode: 'closed', delegatesFocus: false }));
});
test('Should be able to change the focus delegation;', t => {
const Clock = t.context.create({ delegatesFocus: true });
mount(<Clock />);
t.true(attachShadow.calledWith({ mode: 'open', delegatesFocus: true }));
});
test('Should be able to change the nested node;', t => {

@@ -81,0 +90,0 @@

module.exports = {
entry: {
build: ['./example/js/app.js']
build: ['babel-polyfill', './example/js/Default.js']
},

@@ -5,0 +5,0 @@ output: {

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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