diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..6ace206 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,18 @@ +{ + "env": { + "es6": true, + "browser": true, + "node": true + }, + "extends": "eslint:recommended", + "parser": "babel-eslint", + "parserOptions": { + "ecmaFeatures": { + "jsx": true, + "experimentalObjectRestSpread": true + } + }, + "plugins": [ + "react" + ] +} diff --git a/.gitignore b/.gitignore index b947077..5c1bfd3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules/ dist/ +.idea/ diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..43c97e7 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +package-lock=false diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..04c1fba --- /dev/null +++ b/.travis.yml @@ -0,0 +1,8 @@ +language: node_js +node_js: node +addons: + firefox: latest +dist: xenial +services: + - xvfb +script: npm run ci diff --git a/README.md b/README.md index d3d62d0..a138335 100644 --- a/README.md +++ b/README.md @@ -98,13 +98,15 @@ npm i react-to-webcomponent ## API -`reactToWebComponent(ReactComponent, React, ReactDOM)` takes the following: +`reactToWebComponent(ReactComponent, React, ReactDOM, options)` takes the following: - `ReactComponent` - A react component that you want to convert to a Web Component. - `React` - A version of React (or [preact-compat](https://preactjs.com/guide/v10/switching-to-preact)) the component works with. - `ReactDOM` - A version of ReactDOM (or preact-compat) that the component works with. +- `options` - An optional set of parameters. +- `options.shadow` - Use shadow DOM rather than light DOM. A new class inheriting from `HTMLElement` is returned. This class can be directly passed to `customElements.define` as follows: @@ -138,6 +140,19 @@ class WebGreeting extends reactToWebComponent(Greeting, React, ReactDOM) customElements.define("web-greeting", WebGreeting); ``` +Components can also be implemented using [shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM). + +```js +const WebGreeting = reactToWebComponent(Greeting, React, ReactDOM, { shadow: true }); + +customElements.define("web-greeting", WebGreeting); + +var myGreeting = new WebGreeting(); +document.body.appendChild(myGreeting); + +var shadowContent = myGreeting.shadowRoot.children[0]; +``` + ### How it works `reactToWebComponent` creates a constructor function whose prototype is a [Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy). This acts as a trap for any property set on instances of the custom element. When a property is set, the proxy: diff --git a/build.js b/build.js index 653e668..288fca1 100644 --- a/build.js +++ b/build.js @@ -1,4 +1,3 @@ - var stealTools = require("steal-tools"); var globalJS = require("steal-tools/lib/build/helpers/global").js; diff --git a/package.json b/package.json index fdaafce..375929c 100644 --- a/package.json +++ b/package.json @@ -6,8 +6,13 @@ "dependencies": {}, "devDependencies": { "@webcomponents/custom-elements": "^1.2.4", + "babel-eslint": "^10.1.0", "can-stache": "^4.17.20", "can-stache-bindings": "^4.10.9", + "detect-cyclic-packages": "^1.1.0", + "eslint": "^7.11.0", + "eslint-plugin-react": "^7.21.4", + "http-server": "^0.11.1", "preact": "^8.5.2", "preact-compat": "^3.19.0", "prop-types": "^15.7.2", @@ -15,16 +20,23 @@ "react-dom": "^16.9.0", "steal": "^2.2.2", "steal-qunit": "^2.0.0", - "steal-tools": "^2.2.2" + "steal-tools": "^2.2.2", + "test-saucelabs": "0.0.6", + "testee": "^0.9.0" }, "scripts": { "build": "node build.js", + "ci": "npm run test", "preversion": "npm test && npm run build", "version": "git commit -am \"Update version number\" && git checkout -b release && git add -f dist/", "postpublish": "git push --tags && git checkout master && git branch -D release && git push origin master", "release:patch": "npm version patch && npm publish", "release:minor": "npm version minor && npm publish", - "release:major": "npm version major && npm publish" + "release:major": "npm version major && npm publish", + "test": "npm run detect-cycle && npm run eslint && npm run testee", + "detect-cycle": "detect-cyclic-packages", + "eslint": "eslint ./*.js", + "testee": "testee test.html --browsers firefox" }, "repository": { "type": "git", diff --git a/react-to-webcomponent-test.js b/react-to-webcomponent-test.js index 98c17e7..3f4fd9b 100644 --- a/react-to-webcomponent-test.js +++ b/react-to-webcomponent-test.js @@ -64,10 +64,8 @@ QUnit.test("works with attributes set with propTypes", function(assert) { var myGreeting = new MyGreeting(); - var oldError = console.error; console.error = function(message) { assert.ok(message.includes("required"), "got a warning with required"); - oldError = console.error; } fixture.appendChild(myGreeting); @@ -144,3 +142,38 @@ QUnit.test("works within can-stache and can-stache-bindings (propTypes are writa assert.equal(myWelcome.childNodes[0].innerHTML, "Hello, Bohdi", "can update"); }); + + +QUnit.test("works with shadow DOM `options.shadow === true`", function(assert) { + class Welcome extends React.Component { + render() { + return