diff --git a/README.md b/README.md
index 3143cbe..6f565ad 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,4 @@
-ember-cli-stencil
-================================================================================
+# ember-cli-stencil
[![Build Status](https://travis-ci.org/alexlafroscia/ember-cli-stencil.svg?branch=master)](https://travis-ci.org/alexlafroscia/ember-cli-stencil)
[![NPM Version](https://badgen.net/npm/v/ember-cli-stencil)](https://www.npmjs.com/package/ember-cli-stencil)
@@ -11,8 +10,7 @@ Stencil provides a great, opinionated process for defining Web Components (custo
Because of the conventions of Stencil and the Ember CLI respectively, we can wrap up all of that boilerplate so that your custom elements "just work".
-Installation
---------------------------------------------------------------------------------
+## Installation
Start by installing your Stencil components as `npm` modules, as described in the [distribution instructions][distribution] instructions in the guide. Then, install this addon:
@@ -22,14 +20,17 @@ ember install ember-cli-stencil
That's it! Your Stencil components will automatically be detected by the addon and pulled into your application.
-Features
---------------------------------------------------------------------------------
+## Usage
-- [Generating Ember component wrappers](https://github.com/alexlafroscia/ember-cli-stencil/wiki/Ember-component-wrappers)
-- [Custom Events support](https://github.com/alexlafroscia/ember-cli-stencil/wiki/Custom-Events)
+Since Stencil components are detected automatically, you can just start using any Stencil components discovered in your dependencies without any further configuration required. Props can be passed to them, just like other elements, and events listened to through the [`{{on}}` modifier][on-modifier].
-Debugging
---------------------------------------------------------------------------------
+```hbs
+
+ Rendering into the slot
+
+```
+
+## Debugging
If the build seems slow, or you think there are packages missing, you can log some debugging information like so:
@@ -39,12 +40,13 @@ DEBUG=ember-cli-stencil:* ember serve
This will report:
-* Which packages were discovered to be Stencil collections
-* Which files were imported into your `vendor.js` file
-* Which files were added to the `public` folder of the build
+- Which packages were discovered to be Stencil collections
+- Which files were imported into your `vendor.js` file
+- Which files were added to the `public` folder of the build
If there are any issues around judging a file to be a Stencil collection incorrectly or importing the wrong files, please [file an issue][issues].
[stencil]: https://stenciljs.com/
[distribution]: https://stenciljs.com/docs/distribution
[issues]: https://github.com/alexlafroscia/ember-cli-stencil/issues
+[on-modifier]: https://github.com/buschtoens/ember-on-modifier#readme
diff --git a/packages/ember-cli-stencil/addon/-private/generate-component.js b/packages/ember-cli-stencil/addon/-private/generate-component.js
deleted file mode 100644
index 5f48be1..0000000
--- a/packages/ember-cli-stencil/addon/-private/generate-component.js
+++ /dev/null
@@ -1,48 +0,0 @@
-import Component from '@ember/component';
-import { bind } from '@ember/runloop';
-import layout from '../templates/generated-component';
-
-function emberPropertyNameFrom(eventName) {
- return 'on' + eventName.charAt(0).toUpperCase() + eventName.slice(1);
-}
-
-export default function generateComponent(tagName, props = [], events = []) {
- const eventNames = events.map(({ event }) => event);
-
- return Component.extend({
- tagName,
- layout,
-
- attributeBindings: props
- .filter(({ attr }) => attr)
- .map(prop => `${prop.name}:${prop.attr}`),
-
- _invokeEmberEvent(event) {
- const actionProperty = emberPropertyNameFrom(event.type);
-
- this[actionProperty](event);
- },
-
- didInsertElement() {
- this._super(...arguments);
-
- this._boundInvokeEmberEvent = bind(this, this._invokeEmberEvent);
-
- for (const event of eventNames) {
- this.element.addEventListener(event, this._boundInvokeEmberEvent);
- }
-
- for (const prop of props) {
- this.addObserver(prop.name, this._waitForPropigation);
- }
- },
-
- willDestroyElement() {
- for (const event of eventNames) {
- this.element.removeEventListener(event, this._boundInvokeEmberEvent);
- }
-
- this._super(...arguments);
- }
- });
-}
diff --git a/packages/ember-cli-stencil/addon/.gitkeep b/packages/ember-cli-stencil/addon/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/packages/ember-cli-stencil/addon/templates/generated-component.hbs b/packages/ember-cli-stencil/addon/templates/generated-component.hbs
deleted file mode 100644
index 889d9ee..0000000
--- a/packages/ember-cli-stencil/addon/templates/generated-component.hbs
+++ /dev/null
@@ -1 +0,0 @@
-{{yield}}
diff --git a/packages/ember-cli-stencil/app/.gitkeep b/packages/ember-cli-stencil/app/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/packages/ember-cli-stencil/ember-cli-build.js b/packages/ember-cli-stencil/ember-cli-build.js
index baf1593..b50c370 100644
--- a/packages/ember-cli-stencil/ember-cli-build.js
+++ b/packages/ember-cli-stencil/ember-cli-build.js
@@ -3,12 +3,7 @@
const EmberAddon = require('ember-cli/lib/broccoli/ember-addon');
module.exports = function(defaults) {
- let app = new EmberAddon(defaults, {
- 'ember-cli-stencil': {
- generateWrapperComponents: true,
- generateCustomEventsMixin: true
- }
- });
+ let app = new EmberAddon(defaults, {});
/*
This build file specifies the options for the dummy test app of this
diff --git a/packages/ember-cli-stencil/index.js b/packages/ember-cli-stencil/index.js
index a9df1f8..741dbdf 100644
--- a/packages/ember-cli-stencil/index.js
+++ b/packages/ember-cli-stencil/index.js
@@ -7,7 +7,6 @@ const writeFile = require('broccoli-file-creator');
const debug = require('debug');
const StencilCollection = require('./lib/stencil-collection');
-const customEventsMixin = require('./lib/broccoli/dynamically-create-mixin');
const generateInitializer = require('./lib/generate-import-initializer');
module.exports = {
@@ -24,9 +23,7 @@ module.exports = {
return Object.assign(
{
- autoImportCollections: true,
- generateWrapperComponents: true,
- generateCustomEventsMixin: true
+ autoImportCollections: true
},
config['ember-cli-stencil']
);
@@ -88,21 +85,6 @@ module.exports = {
);
},
- treeForAddon(tree) {
- const config = this.addonOptions();
-
- if (config.generateCustomEventsMixin) {
- const merged = new MergeTree([
- tree,
- customEventsMixin(this.stencilCollections)
- ]);
-
- return this._super.treeForAddon.call(this, merged);
- }
-
- return tree;
- },
-
treeForApp(tree) {
const log = debug(`${this.name}:app`);
const config = this.addonOptions();
@@ -119,40 +101,15 @@ module.exports = {
)
);
- tree = MergeTree([tree, importedCollectionsTree]);
- } else {
- log('configuration disabled auto-importing stencil collections');
- }
+ const trees = [importedCollectionsTree];
+
+ if (tree) {
+ trees.push(tree);
+ }
- if (config.generateWrapperComponents) {
- log('configuration enabled generating wrapper components');
-
- const generatedComponents = this.stencilCollections.reduce((acc, dep) => {
- return [
- ...acc,
- ...dep.collection.components.map(component => {
- log('generating component %o from %o', component.tag, dep.name);
-
- const props = component.props;
- const events = component.events;
-
- return writeFile(
- `components/${component.tag}.js`,
- `
- import generateComponent from 'ember-cli-stencil/-private/generate-component';
-
- export default generateComponent('${
- component.tag
- }', ${JSON.stringify(props)}, ${JSON.stringify(events)});
- `
- );
- })
- ];
- }, []);
-
- tree = MergeTree([tree, ...generatedComponents]);
+ tree = MergeTree(trees);
} else {
- log('configuration disabled generating wrapper components');
+ log('configuration disabled auto-importing stencil collections');
}
return tree;
diff --git a/packages/ember-cli-stencil/lib/broccoli/dynamically-create-mixin.js b/packages/ember-cli-stencil/lib/broccoli/dynamically-create-mixin.js
deleted file mode 100644
index 4a187ab..0000000
--- a/packages/ember-cli-stencil/lib/broccoli/dynamically-create-mixin.js
+++ /dev/null
@@ -1,24 +0,0 @@
-const FileCreator = require('broccoli-file-creator');
-
-function mixinWithContent(content) {
- return `
- import Mixin from '@ember/object/mixin';
-
- export default Mixin.create(${JSON.stringify(content)});
- `;
-}
-
-module.exports = function(collections) {
- const customEvents = Object.assign(
- {},
- ...collections
- .map(collection => collection.allEvents)
- .reduce((acc, events) => [...acc, ...events], [])
- .map(({ event }) => ({ [event]: event }))
- );
-
- return new FileCreator(
- 'mixins/custom-events.js',
- mixinWithContent({ customEvents })
- );
-};
diff --git a/packages/ember-cli-stencil/lib/transforms/install-custom-events.js b/packages/ember-cli-stencil/lib/transforms/install-custom-events.js
deleted file mode 100644
index c39394a..0000000
--- a/packages/ember-cli-stencil/lib/transforms/install-custom-events.js
+++ /dev/null
@@ -1,42 +0,0 @@
-const debug = require('debug')('ember-cli-stencil:install-custom-events');
-
-const CUSTOM_EVENTS_MIXIN = 'ember-cli-stencil/mixins/custom-events';
-
-module.exports = function(fileInfo, api) {
- if (fileInfo.source.includes(CUSTOM_EVENTS_MIXIN)) {
- debug('%o already seems to have the mixin applied', fileInfo.path);
- return fileInfo.source;
- }
-
- debug('Running codemod on %o', fileInfo.path);
-
- const j = api.jscodeshift;
- const tree = j(fileInfo.source);
-
- const mixinIdentifier = j.identifier('CustomStencilEvents');
-
- // Import the "custom events" mixin
- const imports = tree.find(j.ImportDeclaration, node => {
- return node.source.value === '@ember/application';
- });
- const applicationVariableName = imports.get('specifiers').value[0].local.name;
-
- const newImport = j.importDeclaration(
- [j.importDefaultSpecifier(mixinIdentifier)],
- j.literal(CUSTOM_EVENTS_MIXIN)
- );
-
- imports.insertAfter(newImport);
-
- // Inject the mixin into the application
- const applicationExtension = tree.find(j.CallExpression, node => {
- return (
- node.callee.type === 'MemberExpression' &&
- node.callee.object.name === applicationVariableName
- );
- });
-
- applicationExtension.get('arguments').unshift(mixinIdentifier);
-
- return tree.toSource();
-};
diff --git a/packages/ember-cli-stencil/package.json b/packages/ember-cli-stencil/package.json
index fbb0895..d432a28 100644
--- a/packages/ember-cli-stencil/package.json
+++ b/packages/ember-cli-stencil/package.json
@@ -48,6 +48,7 @@
"ember-export-application-global": "^2.0.0",
"ember-load-initializers": "^2.0.0",
"ember-maybe-import-regenerator": "^0.1.6",
+ "ember-on-modifier": "^1.0.0",
"ember-qunit": "^4.4.1",
"ember-resolver": "^5.0.1",
"ember-source": "~3.10.0",
diff --git a/packages/ember-cli-stencil/tests/dummy/app/app.js b/packages/ember-cli-stencil/tests/dummy/app/app.js
index b4abb54..b3b2bd6 100644
--- a/packages/ember-cli-stencil/tests/dummy/app/app.js
+++ b/packages/ember-cli-stencil/tests/dummy/app/app.js
@@ -2,9 +2,8 @@ import Application from '@ember/application';
import Resolver from './resolver';
import loadInitializers from 'ember-load-initializers';
import config from './config/environment';
-import CustomEvents from 'ember-cli-stencil/mixins/custom-events';
-const App = Application.extend(CustomEvents, {
+const App = Application.extend({
modulePrefix: config.modulePrefix,
podModulePrefix: config.podModulePrefix,
Resolver
diff --git a/packages/ember-cli-stencil/tests/dummy/app/templates/application.hbs b/packages/ember-cli-stencil/tests/dummy/app/templates/application.hbs
index 38ffc62..e26df08 100644
--- a/packages/ember-cli-stencil/tests/dummy/app/templates/application.hbs
+++ b/packages/ember-cli-stencil/tests/dummy/app/templates/application.hbs
@@ -7,6 +7,6 @@
Binding to an Event
-
+
Action bound to an event
\ No newline at end of file
diff --git a/packages/ember-cli-stencil/tests/integration/custom-events-test.js b/packages/ember-cli-stencil/tests/integration/custom-events-test.js
index a7ccf93..cc1ed9f 100644
--- a/packages/ember-cli-stencil/tests/integration/custom-events-test.js
+++ b/packages/ember-cli-stencil/tests/integration/custom-events-test.js
@@ -13,7 +13,7 @@ module('custom events', function(hooks) {
this.set('customEventHandler', customEventHandler);
await render(hbs`
-
+
Send Event
`);
@@ -23,6 +23,6 @@ module('custom events', function(hooks) {
await click(button);
- assert.verify(customEventHandler());
+ assert.verify(customEventHandler(td.matchers.isA(Event)));
});
});
diff --git a/packages/ember-cli-stencil/tests/integration/generating-ember-components-test.js b/packages/ember-cli-stencil/tests/integration/generating-ember-components-test.js
deleted file mode 100644
index 9d07a60..0000000
--- a/packages/ember-cli-stencil/tests/integration/generating-ember-components-test.js
+++ /dev/null
@@ -1,132 +0,0 @@
-import { module, test } from 'qunit';
-import { setupRenderingTest } from 'ember-qunit';
-import { click, find, render, clearRender } from '@ember/test-helpers';
-import {
- getShadowRoot,
- waitUntilInShadowRoot
-} from 'ember-cli-stencil/test-support';
-import hbs from 'htmlbars-inline-precompile';
-import td from 'testdouble';
-
-module('generating ember components', function(hooks) {
- setupRenderingTest(hooks);
-
- test('it generates an Ember component for each Stencil component', async function(assert) {
- await render(hbs`
- {{demo-passing-props}}
- {{demo-event-emitter}}
- {{demo-rich-props}}
- `);
-
- assert.dom('demo-passing-props').exists();
- assert.dom('demo-event-emitter').exists();
- });
-
- test('it can render into the slots of the Stencil component', async function(assert) {
- await render(hbs`
- {{#demo-event-emitter}}
- Click me!
- {{/demo-event-emitter}}
- `);
-
- assert.dom('demo-event-emitter').hasText('Click me!');
- });
-
- module('passing properties to the underlying element', function() {
- test('binding basic props', async function(assert) {
- this.set('text', 'foo');
-
- await render(hbs`
- {{demo-passing-props text=text}}
- `);
-
- const el = await find('demo-passing-props');
- const shadowRoot = await getShadowRoot(el);
-
- await assert.convergeOn(
- () => shadowRoot.textContent === 'foo',
- 'Has the initial text'
- );
-
- this.set('text', 'bar');
-
- await assert.convergeOn(
- () => shadowRoot.textContent === 'bar',
- 'Has the updated text value'
- );
- });
-
- test('binding complex props', async function(assert) {
- this.set('list', ['foo', 'bar']);
-
- await render(hbs`
- {{demo-rich-props list=list}}
- `);
-
- const el = await find('demo-rich-props');
- const shadowRoot = await getShadowRoot(el);
-
- await assert.convergeOn(() => shadowRoot.textContent === 'foobar');
-
- this.set('list', ['foo', 'bar', 'baz']);
-
- await assert.convergeOn(() => shadowRoot.textContent === 'foobarbaz');
- });
- });
-
- module('event listeners', function() {
- test('it sets up an event listener for each Stencil event', async function(assert) {
- this.handleDemoEvent = td.function('handler');
-
- await render(hbs`
- {{demo-event-emitter onDemoEvent=(action handleDemoEvent)}}
- `);
-
- const el = await find('demo-event-emitter');
- const button = await waitUntilInShadowRoot(el, 'button');
-
- await click(button);
-
- assert.verify(this.handleDemoEvent(td.matchers.isA(CustomEvent)));
- });
-
- test('can access the value emitted from the Stencil component', async function(assert) {
- this.handleDemoEvent = td.function('handler');
-
- await render(hbs`
- {{demo-event-emitter onDemoEvent=(action handleDemoEvent)}}
- `);
-
- const el = await find('demo-event-emitter');
- const button = await waitUntilInShadowRoot(el, 'button');
-
- await click(button);
-
- assert.verify(
- this.handleDemoEvent(
- td.matchers.argThat(event => {
- // Event emitted with `{ foo: 'bar' }`
- return event.detail.foo === 'bar';
- })
- )
- );
- });
-
- test('it removes the event listeners when the component is destroyed', async function(assert) {
- this.handleDemoEvent = td.function('handler');
-
- await render(hbs`
- {{demo-event-emitter onDemoEvent=(action handleDemoEvent)}}
- `);
-
- const el = await find('demo-event-emitter');
- const removeEventListener = td.replace(el, 'removeEventListener');
-
- await clearRender();
-
- assert.verify(
- removeEventListener('demoEvent', td.matchers.isA(Function))
- );
- });
- });
-});
diff --git a/yarn.lock b/yarn.lock
index 321dd3a..e14d029 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2113,7 +2113,7 @@ babel-plugin-debug-macros@^0.1.10, babel-plugin-debug-macros@^0.1.11:
dependencies:
semver "^5.3.0"
-babel-plugin-debug-macros@^0.2.0-beta.6:
+babel-plugin-debug-macros@^0.2.0, babel-plugin-debug-macros@^0.2.0-beta.6:
version "0.2.0"
resolved "https://registry.yarnpkg.com/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.2.0.tgz#0120ac20ce06ccc57bf493b667cf24b85c28da7a"
integrity sha512-Wpmw4TbhR3Eq2t3W51eBAQSdKlr+uAyF0GI4GtPfMCD12Y4cIdpKC9l0RjNTH/P9isFypSqqewMPm7//fnZlNA==
@@ -4834,7 +4834,7 @@ ember-cli-babel@^6.16.0:
ember-cli-version-checker "^2.1.2"
semver "^5.5.0"
-ember-cli-babel@^7.0.0, ember-cli-babel@^7.1.2, ember-cli-babel@^7.7.0, ember-cli-babel@^7.7.3, ember-cli-babel@^7.8.0:
+ember-cli-babel@^7.0.0, ember-cli-babel@^7.1.2, ember-cli-babel@^7.4.2, ember-cli-babel@^7.7.0, ember-cli-babel@^7.7.3, ember-cli-babel@^7.8.0:
version "7.8.0"
resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-7.8.0.tgz#e596500eca0f5a7c9aaee755f803d1542f578acf"
integrity sha512-xUBgJQ81fqd7k/KIiGU+pjpoXhrmmRf9pUrqLenNSU5N+yeNFT5a1+w0b+p1F7oBphfXVwuxApdZxrmAHOdA3Q==
@@ -4993,7 +4993,7 @@ ember-cli-version-checker@^2.0.0, ember-cli-version-checker@^2.1.0:
resolve "^1.3.3"
semver "^5.3.0"
-ember-cli-version-checker@^2.1.2:
+ember-cli-version-checker@^2.1.1, ember-cli-version-checker@^2.1.2:
version "2.2.0"
resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-2.2.0.tgz#47771b731fe0962705e27c8199a9e3825709f3b3"
integrity sha512-G+KtYIVlSOWGcNaTFHk76xR4GdzDLzAS4uxZUKdASuFX0KJE43C6DaqL+y3VTpUFLI2FIkAS6HZ4I1YBi+S3hg==
@@ -5106,6 +5106,15 @@ ember-cli@~3.10.0:
watch-detector "^0.1.0"
yam "^1.0.0"
+ember-compatibility-helpers@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/ember-compatibility-helpers/-/ember-compatibility-helpers-1.2.0.tgz#feee16c5e9ef1b1f1e53903b241740ad4b01097e"
+ integrity sha512-pUW4MzJdcaQtwGsErYmitFRs0rlCYBAnunVzlFFUBr4xhjlCjgHJo0b53gFnhTgenNM3d3/NqLarzRhDTjXRTg==
+ dependencies:
+ babel-plugin-debug-macros "^0.2.0"
+ ember-cli-version-checker "^2.1.1"
+ semver "^5.4.1"
+
ember-disable-prototype-extensions@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/ember-disable-prototype-extensions/-/ember-disable-prototype-extensions-1.1.3.tgz#1969135217654b5e278f9fe2d9d4e49b5720329e"
@@ -5133,6 +5142,25 @@ ember-maybe-import-regenerator@^0.1.6:
ember-cli-babel "^6.0.0-beta.4"
regenerator-runtime "^0.9.5"
+ember-modifier-manager-polyfill@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/ember-modifier-manager-polyfill/-/ember-modifier-manager-polyfill-1.0.3.tgz#6554b70d09a7d3b80d366b72ed482fb9a3e813c0"
+ integrity sha512-d8Uz0BhAZaqzttF4NXTwJ/A8uPrgd7fMho5jh89BfzJAHu5WZfGewX9cbjh3m6f512ZyxkIeeolw3Z5/Jyaujg==
+ dependencies:
+ ember-cli-babel "^7.4.2"
+ ember-cli-version-checker "^2.1.2"
+ ember-compatibility-helpers "^1.2.0"
+
+ember-on-modifier@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/ember-on-modifier/-/ember-on-modifier-1.0.0.tgz#fb89c8d8a69df2f19a11160fa0b054395a5b947c"
+ integrity sha512-OPX5QrNiyXXQ//uN4cFj7gz5pt0rBK5c6LPEMP5iSK2I1J+WtiHM5Kg7mVCM7VziMiRUBVe3wp8CAE26m45hsA==
+ dependencies:
+ broccoli-funnel "^2.0.2"
+ ember-cli-babel "^7.8.0"
+ ember-cli-version-checker "^3.1.3"
+ ember-modifier-manager-polyfill "^1.0.3"
+
ember-qunit@^4.4.1:
version "4.5.1"
resolved "https://registry.yarnpkg.com/ember-qunit/-/ember-qunit-4.5.1.tgz#dc4b0a794fbeb6702a02f28bf19091de0f90fd5a"