diff --git a/README.md b/README.md index a35fac12..6003bb59 100644 --- a/README.md +++ b/README.md @@ -540,7 +540,7 @@ module.exports = { Insert styles at top of `head` tag. -You can pass any parameters to `style.use(anythingHere)` and this value will be passed to `insert` function. These options will be passed to `styleTagTransform` function too. +You can pass any parameters to `style.use(options)` and this value will be passed to `insert` and `styleTagTransform` functions. **webpack.config.js** @@ -554,8 +554,14 @@ module.exports = { { loader: "style-loader", options: { + injectType: "lazyStyleTag", + // Do not forget that this code will be used in the browser and + // not all browsers support latest ECMA features like `let`, `const`, `arrow function expression` and etc, + // we recommend use only ECMA 5 features, + // but it is depends what browsers you want to support insert: function insertIntoTarget(element, options) { - var parent = options.target || document.querySelector("head"); + var parent = options.target || document.head; + parent.appendChild(element); }, }, @@ -570,14 +576,51 @@ module.exports = { Insert styles to the provided element or to the `head` tag if target isn't provided. Now you can inject styles into Shadow DOM (or any other element). -**component.js** +**custom-square.css** + +```css +div { + width: 50px; + height: 50px; + background-color: red; +} +``` + +**custom-square.js** ```js -import style from "./file.css"; +import customSquareStyles from "./custom-square.css"; + +class CustomSquare extends HTMLElement { + constructor() { + super(); + + this.attachShadow({ mode: "open" }); -style.use({ - target: document.querySelector('#myShadowDom').shadowRoot, -}) + const divElement = document.createElement("div"); + + divElement.textContent = "Text content."; + + this.shadowRoot.appendChild(divElement); + + customSquareStyles.use({ target: this.shadowRoot }); + + // You can override injected styles + const bgPurple = new CSSStyleSheet(); + const width = this.getAttribute("w"); + const height = this.getAttribute("h"); + + bgPurple.replace(`div { width: ${width}px; height: ${height}px; }`); + + this.shadowRoot.adoptedStyleSheets = [bgPurple]; + + // `divElement` will have `100px` width, `100px` height and `red` background color + } +} + +customElements.define("custom-square", CustomSquare); + +export default CustomSquare; ``` ### `styleTagTransform` @@ -1033,6 +1076,91 @@ module.exports = { }; ``` +#### Custom Elements (Shadow DOM) + +You can define custom target for your styles for the `lazyStyleTag` type. + +**webpack.config.js** + +```js +module.exports = { + module: { + rules: [ + { + test: /\.css$/i, + use: [ + { + loader: "style-loader", + options: { + injectType: "lazyStyleTag", + // Do not forget that this code will be used in the browser and + // not all browsers support latest ECMA features like `let`, `const`, `arrow function expression` and etc, + // we recommend use only ECMA 5 features, + // but it is depends what browsers you want to support + insert: function insertIntoTarget(element, options) { + var parent = options.target || document.head; + + parent.appendChild(element); + }, + }, + }, + "css-loader", + ], + }, + ], + }, +}; +``` + +Insert styles to the provided element or to the `head` tag if target isn't provided. + +**custom-square.css** + +```css +div { + width: 50px; + height: 50px; + background-color: red; +} +``` + +**custom-square.js** + +```js +import customSquareStyles from "./custom-square.css"; + +class CustomSquare extends HTMLElement { + constructor() { + super(); + + this.attachShadow({ mode: "open" }); + + const divElement = document.createElement("div"); + + divElement.textContent = "Text content."; + + this.shadowRoot.appendChild(divElement); + + customSquareStyles.use({ target: this.shadowRoot }); + + // You can override injected styles + const bgPurple = new CSSStyleSheet(); + const width = this.getAttribute("w"); + const height = this.getAttribute("h"); + + bgPurple.replace(`div { width: ${width}px; height: ${height}px; }`); + + this.shadowRoot.adoptedStyleSheets = [bgPurple]; + + // `divElement` will have `100px` width, `100px` height and `red` background color + } +} + +customElements.define("custom-square", CustomSquare); + +export default CustomSquare; +``` + ## Contributing Please take a moment to read our contributing guidelines if you haven't yet done so. diff --git a/src/index.js b/src/index.js index f0db579c..04cbcb53 100644 --- a/src/index.js +++ b/src/index.js @@ -126,7 +126,8 @@ options.domAPI = ${getdomAPI(isAuto)}; options.insertStyleElement = insertStyleElement; exported.use = function(insertOptions) { - options.insertOptions = insertOptions; + options.options = insertOptions || {}; + if (!(refs++)) { update = API(content, options); } diff --git a/src/runtime/insertStyleElement.js b/src/runtime/insertStyleElement.js index 5295e18e..abd68176 100644 --- a/src/runtime/insertStyleElement.js +++ b/src/runtime/insertStyleElement.js @@ -3,8 +3,7 @@ function insertStyleElement(options) { const style = document.createElement("style"); options.setAttributes(style, options.attributes); - - options.insert(style, options.insertOptions); + options.insert(style, options.options); return style; } diff --git a/src/runtime/styleDomAPI.js b/src/runtime/styleDomAPI.js index a9e2612d..f48b38e3 100644 --- a/src/runtime/styleDomAPI.js +++ b/src/runtime/styleDomAPI.js @@ -18,7 +18,7 @@ function apply(style, options, obj) { // For old IE /* istanbul ignore if */ - options.styleTagTransform(css, style, options.insertOptions); + options.styleTagTransform(css, style, options.options); } function removeStyleElement(style) { diff --git a/test/__snapshots__/lazyStyleTag-options.test.js.snap b/test/__snapshots__/lazyStyleTag-options.test.js.snap new file mode 100644 index 00000000..c478a710 --- /dev/null +++ b/test/__snapshots__/lazyStyleTag-options.test.js.snap @@ -0,0 +1,63 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`lazyStyleTag options should pass "options" to "insert" function and unuse: DOM 1`] = ` +" + style-loader test + + + +

Body

+
+ + + +" +`; + +exports[`lazyStyleTag options should pass "options" to "insert" function and unuse: errors 1`] = `Array []`; + +exports[`lazyStyleTag options should pass "options" to "insert" function and unuse: warnings 1`] = `Array []`; + +exports[`lazyStyleTag options should pass "options" to "insert" function: DOM 1`] = ` +" + style-loader test + + + +

Body

+
+ + + +" +`; + +exports[`lazyStyleTag options should pass "options" to "insert" function: errors 1`] = `Array []`; + +exports[`lazyStyleTag options should pass "options" to "insert" function: warnings 1`] = `Array []`; + +exports[`lazyStyleTag options should pass "options" to "styleTagTransform" function: DOM 1`] = ` +" + style-loader test + + + +

Body

+
+ + + +" +`; + +exports[`lazyStyleTag options should pass "options" to "styleTagTransform" function: errors 1`] = `Array []`; + +exports[`lazyStyleTag options should pass "options" to "styleTagTransform" function: warnings 1`] = `Array []`; diff --git a/test/fixtures/lazy-options-use-unuse.js b/test/fixtures/lazy-options-use-unuse.js new file mode 100644 index 00000000..94cb3c32 --- /dev/null +++ b/test/fixtures/lazy-options-use-unuse.js @@ -0,0 +1,8 @@ +import style from './style.css'; + +style.use({ + insertInto: document.body, + additionalStyles: '.some-element {color: red;}' +}); + +style.unuse(); diff --git a/test/fixtures/lazy-insertOptions.js b/test/fixtures/lazy-options.js similarity index 100% rename from test/fixtures/lazy-insertOptions.js rename to test/fixtures/lazy-options.js diff --git a/test/lazyStyleTag-insertOptions.test.js b/test/lazyStyleTag-insertOptions.test.js deleted file mode 100644 index 53809d7c..00000000 --- a/test/lazyStyleTag-insertOptions.test.js +++ /dev/null @@ -1,53 +0,0 @@ -/* eslint-env browser */ - -import { - compile, - getCompiler, - getEntryByInjectType, - getErrors, - getWarnings, - runInJsDom, -} from "./helpers/index"; - -describe('lazyStyleTag insertOptions', () => { - it(`should pass "insertOption" to "insert" function`, async () => { - expect.assertions(3); - - const entry = getEntryByInjectType("insertOptions.js", 'lazyStyleTag'); - const compiler = getCompiler(entry, { - injectType: 'lazyStyleTag', - insert: (styleTag, options) => { - options.insertInto.appendChild(styleTag); - } - }); - const stats = await compile(compiler); - - runInJsDom("main.bundle.js", compiler, stats, (dom) => { - expect(dom.serialize()).toMatchSnapshot("DOM"); - }); - - expect(getWarnings(stats)).toMatchSnapshot("warnings"); - expect(getErrors(stats)).toMatchSnapshot("errors"); - }); - - it(`should pass "insertOption" to "styleTagTransform" function`, async () => { - expect.assertions(3); - - const entry = getEntryByInjectType("insertOptions.js", 'lazyStyleTag'); - const compiler = getCompiler(entry, { - injectType: 'lazyStyleTag', - styleTagTransform: (css, styleTag, options) => { - // eslint-disable-next-line no-param-reassign - styleTag.innerHTML = `${css}.${options.additionalStyles}\n`; - } - }); - const stats = await compile(compiler); - - runInJsDom("main.bundle.js", compiler, stats, (dom) => { - expect(dom.serialize()).toMatchSnapshot("DOM"); - }); - - expect(getWarnings(stats)).toMatchSnapshot("warnings"); - expect(getErrors(stats)).toMatchSnapshot("errors"); - }); -}); diff --git a/test/lazyStyleTag-options.test.js b/test/lazyStyleTag-options.test.js new file mode 100644 index 00000000..5571052c --- /dev/null +++ b/test/lazyStyleTag-options.test.js @@ -0,0 +1,73 @@ +/* eslint-env browser */ + +import { + compile, + getCompiler, + getEntryByInjectType, + getErrors, + getWarnings, + runInJsDom, +} from "./helpers/index"; + +describe("lazyStyleTag options", () => { + it(`should pass "options" to "insert" function`, async () => { + expect.assertions(3); + + const entry = getEntryByInjectType("options.js", "lazyStyleTag"); + const compiler = getCompiler(entry, { + injectType: "lazyStyleTag", + insert: (styleTag, options) => { + options.insertInto.appendChild(styleTag); + }, + }); + const stats = await compile(compiler); + + runInJsDom("main.bundle.js", compiler, stats, (dom) => { + expect(dom.serialize()).toMatchSnapshot("DOM"); + }); + + expect(getWarnings(stats)).toMatchSnapshot("warnings"); + expect(getErrors(stats)).toMatchSnapshot("errors"); + }); + + it(`should pass "options" to "insert" function and unuse`, async () => { + expect.assertions(3); + + const entry = getEntryByInjectType("options-use-unuse.js", "lazyStyleTag"); + const compiler = getCompiler(entry, { + injectType: "lazyStyleTag", + insert: (styleTag, options) => { + options.insertInto.appendChild(styleTag); + }, + }); + const stats = await compile(compiler); + + runInJsDom("main.bundle.js", compiler, stats, (dom) => { + expect(dom.serialize()).toMatchSnapshot("DOM"); + }); + + expect(getWarnings(stats)).toMatchSnapshot("warnings"); + expect(getErrors(stats)).toMatchSnapshot("errors"); + }); + + it(`should pass "options" to "styleTagTransform" function`, async () => { + expect.assertions(3); + + const entry = getEntryByInjectType("options.js", "lazyStyleTag"); + const compiler = getCompiler(entry, { + injectType: "lazyStyleTag", + styleTagTransform: (css, styleTag, options) => { + // eslint-disable-next-line no-param-reassign + styleTag.innerHTML = `${css}\n${options.additionalStyles}\n`; + }, + }); + const stats = await compile(compiler); + + runInJsDom("main.bundle.js", compiler, stats, (dom) => { + expect(dom.serialize()).toMatchSnapshot("DOM"); + }); + + expect(getWarnings(stats)).toMatchSnapshot("warnings"); + expect(getErrors(stats)).toMatchSnapshot("errors"); + }); +}); diff --git a/test/manual/index.html b/test/manual/index.html index 89155344..7d218ccf 100644 --- a/test/manual/index.html +++ b/test/manual/index.html @@ -93,7 +93,7 @@

Toggle

Custom element

- +
diff --git a/test/manual/src/custom-square.lazy.css b/test/manual/src/custom-square.custom.css similarity index 50% rename from test/manual/src/custom-square.lazy.css rename to test/manual/src/custom-square.custom.css index f8677d42..fdd8138a 100644 --- a/test/manual/src/custom-square.lazy.css +++ b/test/manual/src/custom-square.custom.css @@ -1,5 +1,5 @@ div { - width: 100px; - height: 100px; + width: 50px; + height: 50px; background-color: red; } diff --git a/test/manual/src/custom-square.js b/test/manual/src/custom-square.js index a406dc14..d75d8327 100644 --- a/test/manual/src/custom-square.js +++ b/test/manual/src/custom-square.js @@ -1,13 +1,13 @@ /* eslint-env browser */ /* eslint-disable */ -// import customSquareStyles from './custom-square.lazy.css'; +import customSquareStyles from "./custom-square.custom.css"; class CustomSquare extends HTMLElement { // Specify observed attributes so that // attributeChangedCallback will work static get observedAttributes() { - return ["l"]; + return ["w", "h"]; } constructor() { @@ -15,19 +15,19 @@ class CustomSquare extends HTMLElement { super(); this.attachShadow({ mode: "open" }); - } - connectedCallback() { - const div = document.createElement("div"); + const divElement = document.createElement("div"); + + divElement.textContent = "Text content."; + + this.shadowRoot.appendChild(divElement); - this.shadowRoot.appendChild(div); + customSquareStyles.use({ target: this.shadowRoot }); const bgPurple = new CSSStyleSheet(); + const width = this.getAttribute("w"); + const height = this.getAttribute("h"); - bgPurple.replace(`div { - background: purple; - width: ${this.getAttribute("l")}px; - height: ${this.getAttribute("l")}px; -}`); + bgPurple.replace(`div { width: ${width}px; height: ${height}px; }`); this.shadowRoot.adoptedStyleSheets = [bgPurple]; } diff --git a/test/manual/webpack.config.js b/test/manual/webpack.config.js index de646fe9..24d0374d 100644 --- a/test/manual/webpack.config.js +++ b/test/manual/webpack.config.js @@ -30,6 +30,7 @@ module.exports = { /\.lazy\.css$/i, /\.lazy\.module\.css$/i, /\.link\.css$/i, + /\.custom\.css$/i, ], use: [ { @@ -88,6 +89,32 @@ module.exports = { }, ], }, + { + test: /\.custom\.css$/i, + use: [ + { + loader: require.resolve("../../dist/cjs.js"), + options: { + injectType: "lazyStyleTag", + esModule: ENABLE_ES_MODULE, + insert: function insert(element, options) { + // eslint-disable-next-line + var parent = options.target || document.head; + + parent.appendChild(element); + }, + }, + }, + { + loader: "css-loader", + options: { + sourceMap: ENABLE_SOURCE_MAP, + esModule: ENABLE_PREVIOUS_ES_MODULE, + }, + }, + ], + }, + { test: /\.lazy\.module\.css$/i, exclude: [/\.named-export\.lazy\.module\.css$/i],