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.0.5 to 1.1.0

media/logo.png

2

example/js/weather.js

@@ -83,3 +83,3 @@ import React, { Component, PropTypes } from 'react';

return (
<ShadowDOM cssDocuments="css/country.css">
<ShadowDOM include={['css/country.css', 'css/default.css']}>

@@ -86,0 +86,0 @@ <div className="weather">

{
"name": "react-shadow",
"version": "1.0.5",
"version": "1.1.0",
"description": "Utilise Shadow DOM in React with all the benefits of style encapsulation.",

@@ -5,0 +5,0 @@ "main": "dist/react-shadow.js",

@@ -1,2 +0,2 @@

![Screenshot](media/screenshot.png)
<img src="media/logo.png" width="300" alt="ReactShadow" />

@@ -11,2 +11,4 @@ ![Travis](http://img.shields.io/travis/Wildhoney/ReactShadow.svg?style=flat)

![Screenshot](media/screenshot.png)
---

@@ -22,7 +24,9 @@

export default props => {
return (
<ShadowDOM cssDocuments={['css/core/calendar.css', props.theme]}>
<ShadowDOM include={['css/core/calendar.css', props.theme]}>
<h1>Calendar for {props.date}</h1>
</ShadowDOM>
);
}

@@ -39,2 +43,24 @@ ```

Where components share CSS documents, only one instance of the CSS document will be fetched due to `memoize` of the [`fetchStylesheet`](https://github.com/Wildhoney/ReactShadow/blob/react-15.0/src/react-shadow.js#L22) function.
Where components share documents, only one instance will be fetched due to `memoize` of the [`fetchInclude`](https://github.com/Wildhoney/ReactShadow/blob/master/src/react-shadow.js#L23) function.
### Inlining Styles
Instead of defining external CSS documents to fetch, you could choose to add all of the component's styles to the component itself by simply embedding a `style` node in your component. Naturally all styles added this way will be encapsulated within the shadow boundary.
```javascript
export default props => {
const styles = `:host { background-color: ${props.theme} }`;
return (
<ShadowDOM>
<div>
<h1>Calendar for {props.date}</h1>
<style type="text/css">{styles}</style>
</div>
</ShadowDOM>
);
}
```
It's worth noting that if you combine this approach with the loading of external CSS documents, you will have 2 `style` (*or more*) nodes in your component.

@@ -6,2 +6,3 @@ import { get as fetch } from 'axios';

import memoize from 'ramda/src/memoize';
import groupBy from 'ramda/src/groupBy';

@@ -19,10 +20,10 @@ /**

/**
* @method fetchStylesheet
* @method fetchInclude
* @param {String} document
* @return {Promise}
*/
const fetchStylesheet = memoize(document => {
const fetchInclude = memoize(document => {
return new Promise(resolve => {
fetch(document).then(response => response.data).then(response => resolve(response)).catch(() => resolve(''));
fetch(document).then(response => response.data).then(resolve).catch(() => resolve(''));
});

@@ -33,2 +34,19 @@

/**
* @constant includeMap
* @type {Object}
*/
const includeMap = [
{
extensions: ['js'], tag: 'script', attrs: {
type: 'text/javascript'
}
},
{
extensions: ['css'], tag: 'style', attrs: {
type: 'text/css'
}
}
];
/**
* @class ShadowDOM

@@ -45,3 +63,3 @@ * @extends Component

children: PropTypes.node.isRequired,
cssDocuments: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
include: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
nodeName: PropTypes.string,

@@ -56,3 +74,3 @@ boundaryMode: PropTypes.oneOf(['open', 'closed'])

static defaultProps = {
cssDocuments: [],
include: [],
nodeName: 'span',

@@ -92,3 +110,3 @@ boundaryMode: 'open'

const root = node.attachShadow ? node.attachShadow({ mode: this.props.boundaryMode }) : node.createShadowRoot();
const cssDocuments = this.props.cssDocuments;
const include = Array.isArray(this.props.include) ? this.props.include : [this.props.include];
const container = this.getContainer();

@@ -99,5 +117,5 @@

render(container, root);
!cssDocuments.length && this.setState({ root });
!include.length && this.setState({ root });
if (cssDocuments.length) {
if (include.length) {

@@ -107,3 +125,3 @@ // Otherwise we'll fetch and attach the passed in stylesheets which need to be

this.setState({ resolving: true, root });
this.attachStylesheets(this.props.cssDocuments);
this.attachIncludes(include);

@@ -128,32 +146,35 @@ }

/**
* @method attachStylesheets
* @param cssDocuments {Array|String}
* @method attachIncludes
* @param include {Array|String}
* @return {void}
*/
attachStylesheets(cssDocuments) {
attachIncludes(include) {
const styleElement = document.createElement('style');
styleElement.setAttribute('type', 'text/css');
const documents = Array.isArray(cssDocuments) ? cssDocuments : [cssDocuments];
// Group all of the includes by their extension.
const groupedFiles = groupBy(file => file.extension)(include.map(path => ({ path, extension: path.split('.').pop() })));
/**
* @method insertStyleElement
* @param {Array} cssDocuments
* @return {void}
*/
const insertStyleElement = cssDocuments => {
const includeFiles = Object.keys(groupedFiles).map(extension => {
styleElement.innerHTML = cssDocuments.reduce((accumulator, document) => {
return `${accumulator} ${document}`;
});
const nodeData = includeMap.find(model => model.extensions.includes(extension));
const files = groupedFiles[extension].map(model => model.path);
this.state.root.appendChild(styleElement);
if (!nodeData) {
raise(`Files with extension of "${extension}" are unsupported`);
}
};
const containerElement = document.createElement(nodeData.tag);
Promise.all(documents.map(fetchStylesheet)).then(cssDocuments => {
insertStyleElement(cssDocuments);
this.setState({ resolving: false });
// 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 }));
}

@@ -160,0 +181,0 @@

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

test('Should be able to include CSS documents', t => {
test('Should be able to include external documents', t => {

@@ -104,2 +104,3 @@ return new Promise(resolve => {

const firstStylesheet = '* { border: 1px solid red }';
const firstJavaScript = 'console.log("Da comrade!")';
const secondStylesheet = '* { background-color: orange }';

@@ -109,4 +110,6 @@

t.context.mockAdapter.onGet('/second.css').reply(200, secondStylesheet);
t.context.mockAdapter.onGet('/first.js').reply(200, firstJavaScript);
t.context.mockAdapter.onGet('/second.js').reply(404);
const Clock = t.context.create({ cssDocuments: ['/first.css', '/second.css'] });
const Clock = t.context.create({ include: ['/first.css', '/first.js', '/second.css', '/second.js'] });
const wrapper = mount(<Clock />);

@@ -120,6 +123,15 @@

const style = { text: () => host.node.querySelector('style').innerHTML };
const styles = Array.from(host.node.querySelectorAll('style'));
const style = { text: () => styles[0].innerHTML };
t.is(styles.length, 1);
t.is(style.text(), `${firstStylesheet} ${secondStylesheet}`);
const scripts = Array.from(host.node.querySelectorAll('script'));
const script = { text: () => scripts[0].innerHTML };
t.is(scripts.length, 1);
t.is(script.text(), `${firstJavaScript}`);
t.true(host.hasClass('simple-clock'));
t.true(host.hasClass('resolved'));
resolve();

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

test('Should be able to raise exceptions from sanity checks;', t => {
test('Should be able to raise necessary exceptions for happier devs;', t => {

@@ -148,2 +160,7 @@ // Prevent React from throwing errors it would otherwise throw with the below assertions.

t.throws(() => {
t.context.mockAdapter.onGet('/document.png').reply(200, 'data');
mount(<ShadowDOM include="/document.png"><div><h1>Picture</h1></div></ShadowDOM>);
}, 'ReactShadow: Files with extension of "png" are unsupported.');
});

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

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