diff --git a/Gruntfile.js b/Gruntfile.js index 0f1da875..74634002 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -272,6 +272,8 @@ module.exports = function(grunt) { // Default task - prints to the console the tasks that are available to be run from the command line // grunt.registerTask('default', function() { + grunt.log.writeln('The Basic Web Components project now uses gulp rather than grunt.'); + /* grunt.log.writeln('grunt commands this project supports:\n'); grunt.log.writeln(' grunt build (builds consolidated basic-web-components.js, all package distributions, all documentation, and all tests)'); grunt.log.writeln(' grunt devbuild (same as build minus building the documentation)'); @@ -281,6 +283,7 @@ module.exports = function(grunt) { grunt.log.writeln(' grunt set-version:version (updates package.json version values and dependencies. Ex: grunt set-version:1.0.30)'); grunt.log.writeln(' grunt saucelabs (Runs SauceLabs tests. You must set environment variables SAUCE_USERNAME and SAUCE_ACCESS_KEY.)'); grunt.log.writeln(' grunt watch (builds and watches changes to project files)'); + */ }); // @@ -294,14 +297,14 @@ module.exports = function(grunt) { // // This task makes use of the buildList global array. // - grunt.registerTask('build', ['browserify:buildFiles', 'docs', 'jshint']); + // grunt.registerTask('build', ['browserify:buildFiles', 'docs', 'jshint']); // // The devbuild task is callable from the command line and is similar to the build task but doesn't // build the documentation files. This is meant as a quicker task for developers actively working // on code. // - grunt.registerTask('devbuild', ['browserify:buildFiles', 'jshint']); + // grunt.registerTask('devbuild', ['browserify:buildFiles', 'jshint']); // // The docs task is callable from the command line. This task builds each package's @@ -309,6 +312,7 @@ module.exports = function(grunt) { // // This task makes use of the docsList global array. // + /* grunt.registerTask('docs', function() { const done = this.async(); return mapAndChain(docsList, doc => buildMarkdownDoc(doc, grunt)) @@ -319,30 +323,31 @@ module.exports = function(grunt) { grunt.log.error(err) ); }); + */ // // The lint task is callable from the command line and executes the jshint task defined // in the Grunt config. This task looks for JavaScript warnings/errors. // - grunt.registerTask('lint', ['jshint']); + // grunt.registerTask('lint', ['jshint']); // // The saucelabs task is callable from the command line and executes unit tests on SauceLabs // - grunt.registerTask('saucelabs', ['connect', 'saucelabs-mocha']); + // grunt.registerTask('saucelabs', ['connect', 'saucelabs-mocha']); // // The test task is callable from the command line and executes the mocha task defined // in the Grunt config. This task executes the monorepo's test suite. // - grunt.registerTask('test', ['mocha']); + // grunt.registerTask('test', ['mocha']); // // The watch task is callable from the command line and executes the browserify:watch task // defined in the Grunt config. This task performs a build and then watches for changes // for instant update during development. // - grunt.registerTask('watch', ['browserify:watch']); + // grunt.registerTask('watch', ['browserify:watch']); // // The npm-publish task is callable from the command line and performs a publish operation diff --git a/gulp/lib/allPackages.js b/gulp/lib/allPackages.js new file mode 100644 index 00000000..fa406332 --- /dev/null +++ b/gulp/lib/allPackages.js @@ -0,0 +1,19 @@ +/*jslint node: true */ +'use strict'; + +const fs = require('fs'); +const path = require('path'); + +// +// allPackages is the global array of npm-publishable packages in this monorepo. +// This is all folders inside the ./packages folder that start with the prefix +// "basic-". +// +const PACKAGE_FOLDER = './packages'; +const allPackages = fs.readdirSync(PACKAGE_FOLDER).filter(fileName => { + const filePath = path.join(PACKAGE_FOLDER, fileName); + const stat = fs.statSync(filePath); + return stat && stat.isDirectory() && fileName.startsWith('basic-'); +}); + +module.exports = allPackages; \ No newline at end of file diff --git a/gulp/tasks/browserify.js b/gulp/tasks/browserify.js new file mode 100644 index 00000000..a5cc1901 --- /dev/null +++ b/gulp/tasks/browserify.js @@ -0,0 +1,126 @@ +/*jslint node: true */ +'use strict'; + +const gulp = require('gulp'); +const gutil = require('gulp-util'); +const glob = require('glob'); +const babelify = require('babelify') +const browserify = require('browserify'); +const watchify = require('watchify'); +const buffer = require('vinyl-buffer'); +const vinylStream = require('vinyl-source-stream'); +const sourceMaps = require('gulp-sourcemaps'); +const uglify = require('gulp-uglify'); +const allPackages = require('../lib/allPackages'); + +// +// Build the global buildList object for use in browserifyTask +// +function buildBuildList() { + const buildList = { + 'build/tests.js': allPackages.map(pkg => `packages/${pkg}/test/*.js`) + }; + allPackages.forEach(pkg => { + buildList[`packages/${pkg}/dist/${pkg}.js`] = [`packages/${pkg}/globals.js`]; + }); + buildList['packages/demos/dist/demos.js'] = ['packages/demos/src/*.js']; + return buildList; +} +const buildList = buildBuildList(); + +const watchifyTask = function(done) { + browserifyHelperTask(true, done); +} + +const browserifyTask = function(done) { + browserifyHelperTask(false, done); +} + +const browserifyHelperTask = function(watch, done) { + let processedCount = 0; + let bundlerCount = 0; + let bundlers = []; + + function bundleIt(bundler) { + bundler.bundler + .bundle() + .pipe(vinylStream(bundler.outputFile)) + .pipe(buffer()) // Convert to gulp pipeline + .pipe(sourceMaps.init({loadMaps : true})) // Strip inline source maps + .pipe(uglify()) // Minimize + .on('error', gutil.log) + .pipe(sourceMaps.write('./')) // Relative to bundler.outputDir below + .pipe(gulp.dest(bundler.outputDir)) + .on('end', function() { + gutil.log(`Processed ${bundler.source} and wrote ${bundler.outputDir}${bundler.outputFile}`); + processedCount++; + if (processedCount >= bundlerCount) { + if (watch) { + // Do not call task completion callback in the watch case + gutil.log('Now watching for changes...') + } + else { + done(); + } + } + }); + } + + gutil.log('Preparing build...'); + + for (let key in buildList) { + let entries = []; + + buildList[key].forEach(globItem => { + let a = glob.sync(globItem); + Array.prototype.push.apply(entries, a); + }); + + const props = watch ? { + entries: entries, + debug: true, + cache: {}, + packageCache: {}, + plugin: [watchify] + } : { + entries: entries, + debug: true + } + + let bundler = browserify(props); + if (watch) { + bundler.on('update', function() { + bundleIt(this.bundlerData); + }); + } + + let bundlerData = { + bundler: bundler, + source: entries, + outputFile: key.split('/').pop(), + outputDir: key.substring(0, key.lastIndexOf('/') + 1) + }; + + // Attach bundlerData to the bundler object so we can fetch + // details about the bundler in the update event + bundler.bundlerData = bundlerData; + + bundlers.push(bundlerData); + } + + bundlerCount = bundlers.length; + + bundlers.forEach(bundler => { + // + // Remember: we have .babelrc in the root specifying the ES2015 preset, + // and the babelify transform specified in package.json. + // This was necessary for the Grunt build. The following line is + // therefore unnecessary: + // + // bundler.bundler.transform(babelify, {presets: ['es2015']}); + + bundleIt(bundler); + }); +}; + +module.exports = {browserifyTask: browserifyTask, watchifyTask: watchifyTask}; \ No newline at end of file diff --git a/gulp/tasks/docs.js b/gulp/tasks/docs.js new file mode 100644 index 00000000..43161022 --- /dev/null +++ b/gulp/tasks/docs.js @@ -0,0 +1,184 @@ +/*jslint node: true */ +'use strict'; + +const fs = require('fs'); +const jsDocParse = require('jsdoc-parse'); +const dmd = require('dmd'); +const Readable = require('stream').Readable; +const gutil = require('gulp-util'); +const allPackages = require('../lib/allPackages'); + +// +// Build the global docsList array for use in building the package's README.md documentation +// +function buildDocsList() { + const packagesWithoutBuiltDocs = [ + 'basic-component-mixins', + 'basic-web-components' + ]; + const ary = allPackages.filter(item => { + return packagesWithoutBuiltDocs.indexOf(item) < 0; + }).map(item => { + return { + src: `packages/${item}/src/*.js`, + dest: `packages/${item}/README.md`}; + }); + + return ary.concat(buildMixinsDocsList()); +} +const docsList = buildDocsList(); + +// +// Build the portion of docsList that represents the individual source files within +// the basic-component-mixins directory. +// +function buildMixinsDocsList() { + return fs.readdirSync('packages/basic-component-mixins/src').filter(file => { + return file.indexOf('.js') == file.length - 3; + }).map(file => { + const fileRoot = file.replace('.js', ''); + return { + src: `packages/basic-component-mixins/src/${file}`, + dest: `packages/basic-component-mixins/docs/${fileRoot}.md` }; + }); +} + +function buildMarkdownDoc(docItem) { + gutil.log('Building ' + docItem.dest + ' from ' + docItem.src); + + return parseScriptToJSDocJSON(docItem.src) + .then(json => { + return mergeMixinDocs(json); + }) + .then(json => { + // Sort the array, leaving the order:0 item alone at the + // front of the list (the class identifier section) + json.sort((a, b) => { + if (a.order === 0) { return -1; } + if (b.order === 0) { return 1; } + + return a.name.localeCompare(b.name); + }); + + // Set the order value + json.map((item, index) => { + item.order = index; + }); + + // Convert the JSON to Markdown + return parseJSONToMarkdown(json); + }) + .then(function(string) { + // Write to the output markdown file + return new Promise(function(resolve, reject) { + fs.writeFile(docItem.dest, string, 'utf-8', function (err) { + if (err) { + return reject(err); + } + resolve(); + }); + }); + }); +} + +function parseScriptToJSDocJSON(src) { + return new Promise((resolve, reject) => { + // Start by parsing the jsdoc into a stream which will contain + // the jsdoc represented in JSON + const stream = jsDocParse({src: src}); + + // Convert the stream to jsdoc JSON + let string = ''; + stream.setEncoding('utf8'); + stream.on('data', chunk => { + string += chunk; + }) + .on('end', () => { + const json = JSON.parse(string); + resolve(json); + }) + .on('error', err => { + reject(err); + }); + }); +} + +function parseJSONToMarkdown(json) { + return new Promise(function(resolve, reject) { + // Create a new readable stream, holding the stringified JSON + let string = ''; + const s = new Readable(); + s._read = function noop() {}; + s.push(JSON.stringify(json)); + s.push(null); + + // Use dmd to create the markdown string which we will + // write to an output .md file (NYI) + const partials = [ + './gulp/templates/main.hbs', + './gulp/templates/scope.hbs', + './gulp/templates/mixes.hbs', + './gulp/templates/mixin-linked-type-list.hbs']; + const dmdStream = dmd({partial: partials, 'global-index-format': 'none', 'group-by': ['none']}); + s.pipe(dmdStream); + dmdStream.setEncoding('utf8'); + dmdStream.on('data', data => { + string += data; + }) + .on('end', () => { + // string now holds the markdown text + resolve(string); + }) + .on('error', err => { + reject(err); + }); + }); +} + +function mergeMixinDocs(componentJson) { + if (componentJson[0].mixes == null || componentJson[0].mixes === undefined) { + return componentJson; + } + + const mixins = componentJson[0].mixes.map(mixin => { + return 'packages/basic-component-mixins/src/' + mixin + '.js'; + }); + + const hostId = componentJson[0].id; + return mapAndChain(mixins, mixin => mergeMixinIntoBag(mixin, componentJson, hostId)) + .then(() => + componentJson + ); +} + +function mergeMixinIntoBag(mixinPath, componentJson, hostId) { + return parseScriptToJSDocJSON(mixinPath) + .then(mixinJson => { + for (let i = 1; i < mixinJson.length; i++) { + if (mixinJson[i].memberof != null && mixinJson[i].memberof != hostId) { + mixinJson[i].originalmemberof = mixinJson[i].memberof; + mixinJson[i].memberof = hostId; + } + componentJson.push(mixinJson[i]); + } + }); +} + +// Apply the given promise-returning function to each member of the array. +// Ensure each promise completes before starting the next one to avoid +// spinning up too many file operations at once. This is effectively like +// Promise.all(), while ensuring that the items are processed in a completely +// sequential order. +function mapAndChain(array, promiseFn) { + // Start the promise chain with a resolved promise. + return array.reduce((chain, item) => chain.then(() => promiseFn(item)), Promise.resolve()); +} + + +const docsTask = function() { + return mapAndChain(docsList, doc => buildMarkdownDoc(doc)) + .then(() => gutil.log('All documentation complete')) + .catch(err => gutil.log(`error: ${err}`)); +}; + +module.exports = docsTask; \ No newline at end of file diff --git a/gulp/tasks/help.js b/gulp/tasks/help.js new file mode 100644 index 00000000..f0af0996 --- /dev/null +++ b/gulp/tasks/help.js @@ -0,0 +1,24 @@ +/*jslint node: true */ +'use strict'; + +const gulp = require('gulp'); +const gutil = require('gulp-util'); + +// +// Help task - prints to the console the tasks that are available to be run from the command line +// +function helpTask() { + gutil.log(`gulp commands this project supports: + + gulp build (builds all packages, docs, and tests) + gulp devbuild (same as build minus building the documentation) + gulp docs (builds all packages README.md files) + gulp lint (runs jshint on all .js files) + gulp watch (builds and watches changes to project files) + `); + // gulp npm-publish:package-name|* (publishes packages/package-name or all packages (packages/*) to npm) + // gulp set-version:version (updates package.json version values and dependencies. Ex: gulp set-version:1.0.30) + // gulp saucelabs (Runs SauceLabs tests. You must set environment variables SAUCE_USERNAME and SAUCE_ACCESS_KEY.) +} + +module.exports = helpTask; \ No newline at end of file diff --git a/gulp/tasks/lint.js b/gulp/tasks/lint.js new file mode 100644 index 00000000..7ba04af6 --- /dev/null +++ b/gulp/tasks/lint.js @@ -0,0 +1,23 @@ +/*jslint node: true */ +'use strict'; + +const gulp = require('gulp'); +const gutil = require('gulp-util'); +const jshint = require('gulp-jshint'); + +const lintTask = function() { + const lintFiles = [ + 'gulpfile.js', + 'packages/**/*.js', + '!packages/**/dist/**', + '!packages/**/lib/**', + '!packages/**/bower_components/**', + 'test/**/*.js' + ]; + + return gulp.src(lintFiles) + .pipe(jshint()) + .pipe(jshint.reporter('default')); +} + +module.exports = lintTask; \ No newline at end of file diff --git a/gulp/templates/main.hbs b/gulp/templates/main.hbs new file mode 100644 index 00000000..9cc0bbd4 --- /dev/null +++ b/gulp/templates/main.hbs @@ -0,0 +1,3 @@ +# API Documentation +{{>main-index~}} +{{>all-docs~}} \ No newline at end of file diff --git a/gulp/templates/mixes.hbs b/gulp/templates/mixes.hbs new file mode 100644 index 00000000..42e144ae --- /dev/null +++ b/gulp/templates/mixes.hbs @@ -0,0 +1,3 @@ +{{#if mixes~}} + **Mixes**: {{>mixin-linked-type-list types=mixes delimiter=", " }} +{{/if}} \ No newline at end of file diff --git a/gulp/templates/mixin-linked-type-list.hbs b/gulp/templates/mixin-linked-type-list.hbs new file mode 100644 index 00000000..8a6cbd0f --- /dev/null +++ b/gulp/templates/mixin-linked-type-list.hbs @@ -0,0 +1,4 @@ +{{#each types~}} + [{{this}}](../basic-component-mixins/docs/{{this}}.md) + {{#unless @last}}{{{../../delimiter}}}{{/unless~}} +{{/each}} \ No newline at end of file diff --git a/gulp/templates/scope.hbs b/gulp/templates/scope.hbs new file mode 100644 index 00000000..0649a0d3 --- /dev/null +++ b/gulp/templates/scope.hbs @@ -0,0 +1,12 @@ +{{#if scope}} + **Kind**: {{#if (equal kind "event") ~}} + event emitted{{#if memberof}} by {{#if originalmemberof}}{{>link to=memberof}}. Defined by [{{originalmemberof}}](../basic-component-mixins/docs/{{originalmemberof}}.md) mixin.{{else~}} + {{>link to=memberof}}{{/if}}{{/if}} + {{else~}} + {{scope}} {{#if virtual}}abstract {{/if}}{{kindInThisContext}}{{#if memberof}} of {{#if originalmemberof}}{{>link to=memberof}}. Defined by [{{originalmemberof}}](../basic-component-mixins/docs/{{originalmemberof}}.md) mixin.{{else~}} + {{>link to=memberof}}{{/if}}{{/if}} + {{/if~}} + {{else~}} + {{#if isExported}}**Kind**: Exported {{kind}} + {{/if~}} +{{/if~}} \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 00000000..ff007a33 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,36 @@ +/*jslint node: true */ +'use strict'; + +const gulp = require('gulp'); + +const browserifyTask = require('./gulp/tasks/browserify').browserifyTask; +const watchifyTask = require('./gulp/tasks/browserify').watchifyTask; +const docsTask = require('./gulp/tasks/docs'); +const helpTask = require('./gulp/tasks/help'); +const lintTask = require('./gulp/tasks/lint'); + +// +// Naming convention for tasks: +// taskName[-taskDependency[-taskDependency-[...]]] +// +// Example: +// lint: Simply runs the lint task +// lint-browserify: Runs the lint task with a dependency on browserify +// lint-docs-browserify: Runs the lint taks with a dependency first on docs, +// then browserify +// + +// Private +gulp.task('browserify', [], browserifyTask); +gulp.task('docs-browserify', ['browserify'], docsTask); +gulp.task('help', [], helpTask); +gulp.task('lint-docs-browserify', ['docs-browserify'], lintTask); +gulp.task('lint-browserify', ['browserify'], lintTask); + +// Public +gulp.task('build', ['browserify', 'docs-browserify', 'lint-docs-browserify']); +gulp.task('devbuild', ['browserify', 'lint-browserify']); +gulp.task('default', ['help']); +gulp.task('docs', [], docsTask); +gulp.task('lint', [], lintTask); +gulp.task('watch', [], watchifyTask); diff --git a/package.json b/package.json index 03d87193..5a2b3594 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "dependencies": { "babel-preset-es2015": "^6.6.0", "babelify": "^7.3.0", + "browserify": "^13.1.1", "chai": "^3.5.0", "grunt": "^0.4.5", "grunt-browserify": "^4.0.1", @@ -20,9 +21,18 @@ "grunt-contrib-jshint": "^0.11.3", "grunt-contrib-watch": "^0.6.1", "grunt-jsdoc-to-markdown": "^1.2.0", - "grunt-mocha": "^0.4.15", + "grunt-mocha": "^1.0.2", "grunt-saucelabs": "^8.6.2", "grunt-shell": "^1.1.2", + "gulp": "^3.9.1", + "gulp-jshint": "^2.0.3", + "gulp-rename": "^1.2.2", + "gulp-sourcemaps": "^2.2.0", + "gulp-uglify": "^2.0.0", + "gulp-util": "^3.0.7", + "vinyl-buffer": "^1.0.0", + "vinyl-source-stream": "^1.1.0", + "watchify": "^3.7.0", "web-animations-js": "^2.2.1" }, "browserify": { diff --git a/packages/basic-animation-stage/dist/basic-animation-stage.js b/packages/basic-animation-stage/dist/basic-animation-stage.js index df3d71e3..2e7b1c28 100644 --- a/packages/basic-animation-stage/dist/basic-animation-stage.js +++ b/packages/basic-animation-stage/dist/basic-animation-stage.js @@ -1,3339 +1,3 @@ -(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o\n :host {\n overflow: hidden;\n position: relative;\n }\n\n #container ::slotted(*) {\n height: 100%;\n object-fit: contain;\n position: absolute;\n width: 100%;\n will-change: transform;\n }\n \n\n
\n \n
\n '; - } - }]); - - return AnimationStage; -}(base); - -customElements.define('basic-animation-stage', AnimationStage); -exports.default = AnimationStage; - -},{"../../basic-component-mixins/src/ContentItemsMixin":5,"../../basic-component-mixins/src/DistributedChildrenContentMixin":6,"../../basic-component-mixins/src/FractionalSelectionMixin":8,"../../basic-component-mixins/src/SelectionAnimationMixin":9,"../../basic-component-mixins/src/SelectionAriaActiveMixin":10,"../../basic-component-mixins/src/SingleSelectionMixin":13,"../../basic-component-mixins/src/symbols":17,"../../basic-element-base/src/ElementBase":19}],3:[function(require,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; - -var _safeAttributes = require('./safeAttributes'); - -var _safeAttributes2 = _interopRequireDefault(_safeAttributes); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } - -function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - -// Memoized maps of attribute to property names and vice versa. -var attributeToPropertyNames = {}; -var propertyNamesToAttributes = {}; - -/* Exported function extends a base class with AttributeMarshalling. */ - -exports.default = function (base) { - - /** - * Mixin which marshalls attributes to properties and vice versa. - * - * If your component exposes a setter for a property, it's generally a good - * idea to let devs using your component be able to set that property in HTML - * via an element attribute. You can code that yourself by writing an - * `attributeChangedCallback`, or you can use this mixin to get a degree of - * automatic support. - * - * This mixin implements an `attributeChangedCallback` that will attempt to - * convert a change in an element attribute into a call to the corresponding - * property setter. Attributes typically follow hyphenated names ("foo-bar"), - * whereas properties typically use camelCase names ("fooBar"). This mixin - * respects that convention, automatically mapping the hyphenated attribute - * name to the corresponding camelCase property name. - * - * Example: You define a component using this mixin: - * - * class MyElement extends AttributeMarshallingMixin(HTMLElement) { - * get fooBar() { return this._fooBar; } - * set fooBar(value) { this._fooBar = value; } - * } - * customElements.define('my-element', MyElement); - * - * If someone then instantiates your component in HTML: - * - * - * - * Then, after the element has been upgraded, the `fooBar` setter will - * automatically be invoked with the initial value "Hello". - * - * For the time being, this mixin only supports string-valued properties. - * If you'd like to convert string attributes to other types (numbers, - * booleans), you need to implement `attributeChangedCallback` yourself. - */ - var AttributeMarshalling = function (_base) { - _inherits(AttributeMarshalling, _base); - - function AttributeMarshalling() { - _classCallCheck(this, AttributeMarshalling); - - return _possibleConstructorReturn(this, (AttributeMarshalling.__proto__ || Object.getPrototypeOf(AttributeMarshalling)).apply(this, arguments)); - } - - _createClass(AttributeMarshalling, [{ - key: 'attributeChangedCallback', - - - /* - * Handle a change to the attribute with the given name. - */ - value: function attributeChangedCallback(attributeName, oldValue, newValue) { - if (_get(AttributeMarshalling.prototype.__proto__ || Object.getPrototypeOf(AttributeMarshalling.prototype), 'attributeChangedCallback', this)) { - _get(AttributeMarshalling.prototype.__proto__ || Object.getPrototypeOf(AttributeMarshalling.prototype), 'attributeChangedCallback', this).call(this); - } - var propertyName = attributeToPropertyName(attributeName); - // If the attribute name corresponds to a property name, set the property. - // Ignore standard HTMLElement properties handled by the DOM. - if (propertyName in this && !(propertyName in HTMLElement.prototype)) { - this[propertyName] = newValue; - } - } - }, { - key: 'connectedCallback', - value: function connectedCallback() { - if (_get(AttributeMarshalling.prototype.__proto__ || Object.getPrototypeOf(AttributeMarshalling.prototype), 'connectedCallback', this)) { - _get(AttributeMarshalling.prototype.__proto__ || Object.getPrototypeOf(AttributeMarshalling.prototype), 'connectedCallback', this).call(this); - } - _safeAttributes2.default.connected(this); - } - }, { - key: 'reflectAttribute', - - - /** - * Set/unset the attribute with the indicated name. - * - * This method exists primarily to handle the case where an element wants to - * set a default property value that should be reflected as an attribute. An - * important limitation of custom element consturctors is that they cannot - * set attributes. A call to `reflectAttribute` during the constructor will - * be deferred until the element is connected to the document. - * - * @param {string} attribute - The name of the *attribute* (not property) to set. - * @param {object} value - The value to set. If null, the attribute will be removed. - */ - value: function reflectAttribute(attribute, value) { - return _safeAttributes2.default.setAttribute(this, attribute, value); - } - - /** - * Set/unset the class with the indicated name. - * - * This method exists primarily to handle the case where an element wants to - * set a default property value that should be reflected as as class. An - * important limitation of custom element consturctors is that they cannot - * set attributes, including the `class` attribute. A call to - * `reflectClass` during the constructor will be deferred until the element - * is connected to the document. - * - * @param {string} className - The name of the class to set. - * @param {object} value - True to set the class, false to remove it. - */ - - }, { - key: 'reflectClass', - value: function reflectClass(className, value) { - return _safeAttributes2.default.toggleClass(this, className, value); - } - }], [{ - key: 'observedAttributes', - get: function get() { - return attributesForClass(this); - } - }]); - - return AttributeMarshalling; - }(base); - - return AttributeMarshalling; -}; - -// Convert hyphenated foo-bar attribute name to camel case fooBar property name. - - -function attributeToPropertyName(attributeName) { - var propertyName = attributeToPropertyNames[attributeName]; - if (!propertyName) { - // Convert and memoize. - var hypenRegEx = /-([a-z])/g; - propertyName = attributeName.replace(hypenRegEx, function (match) { - return match[1].toUpperCase(); - }); - attributeToPropertyNames[attributeName] = propertyName; - } - return propertyName; -} - -function attributesForClass(classFn) { - - // We treat the element base classes as if they have no attributes, since we - // don't want to receive attributeChangedCallback for them. - if (classFn === HTMLElement || classFn === Object) { - return []; - } - - // Get attributes for parent class. - var baseClass = Object.getPrototypeOf(classFn.prototype).constructor; - var baseAttributes = attributesForClass(baseClass); - - // Get attributes for this class. - var propertyNames = Object.getOwnPropertyNames(classFn.prototype); - var setterNames = propertyNames.filter(function (propertyName) { - return typeof Object.getOwnPropertyDescriptor(classFn.prototype, propertyName).set === 'function'; - }); - var attributes = setterNames.map(function (setterName) { - return propertyNameToAttribute(setterName); - }); - - // Merge. - var diff = attributes.filter(function (attribute) { - return baseAttributes.indexOf(attribute) < 0; - }); - return baseAttributes.concat(diff); -} - -// Convert a camel case fooBar property name to a hyphenated foo-bar attribute. -function propertyNameToAttribute(propertyName) { - var attribute = propertyNamesToAttributes[propertyName]; - if (!attribute) { - // Convert and memoize. - var uppercaseRegEx = /([A-Z])/g; - attribute = propertyName.replace(uppercaseRegEx, '-$1').toLowerCase(); - } - return attribute; -} - -},{"./safeAttributes":16}],4:[function(require,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } - -function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - -/* Exported function extends a base class with Composable. */ -exports.default = function (base) { - - /** - * Mixin to make a class more easily composable with other mixins. - * - * This mixin contributes a `compose` method that applies a set of mixin - * functions and returns the resulting new class. This sugar can make the - * application of many mixins at once easier to read. - */ - var Composable = function (_base) { - _inherits(Composable, _base); - - function Composable() { - _classCallCheck(this, Composable); - - return _possibleConstructorReturn(this, (Composable.__proto__ || Object.getPrototypeOf(Composable)).apply(this, arguments)); - } - - _createClass(Composable, null, [{ - key: 'compose', - - - /** - * Apply a set of mixin functions or mixin objects to the present class and - * return the new class. - * - * Instead of writing: - * - * let MyClass = Mixin1(Mixin2(Mixin3(Mixin4(Mixin5(BaseClass))))); - * - * You can write: - * - * let MyClass = ComposableMixin(BaseClass).compose( - * Mixin1, - * Mixin2, - * Mixin3, - * Mixin4, - * Mixin5 - * ); - * - * This function can also take mixin objects. A mixin object is just a - * shorthand for a mixin function that creates a new subclass with the given - * members. The mixin object's members are *not* copied directly onto the - * prototype of the base class, as with traditional mixins. - * - * In addition to providing syntactic sugar, this mixin can be used to - * define a class in ES5, which lacks ES6's `class` keyword. - * - * @param {...mixins} mixins - A set of mixin functions or objects to apply. - */ - value: function compose() { - for (var _len = arguments.length, mixins = Array(_len), _key = 0; _key < _len; _key++) { - mixins[_key] = arguments[_key]; - } - - // We create a new subclass for each mixin in turn. The result becomes - // the base class extended by any subsequent mixins. It turns out that - // we can use Array.reduce() to concisely express this, using the current - // object as the seed for reduce(). - return mixins.reduce(composeClass, this); - } - }]); - - return Composable; - }(base); - - return Composable; -}; - -// Properties defined by Object that we don't want to mixin. - - -var NON_MIXABLE_OBJECT_PROPERTIES = ['constructor']; - -/* - * Apply the mixin to the given base class to return a new class. - * The mixin can either be a function that returns the modified class, or a - * plain object whose members will be copied to the new class' prototype. - */ -function composeClass(base, mixin) { - if (typeof mixin === 'function') { - // Mixin function - return mixin(base); - } else { - // Mixin object - var Subclass = function (_base2) { - _inherits(Subclass, _base2); - - function Subclass() { - _classCallCheck(this, Subclass); - - return _possibleConstructorReturn(this, (Subclass.__proto__ || Object.getPrototypeOf(Subclass)).apply(this, arguments)); - } - - return Subclass; - }(base); - - copyOwnProperties(mixin, Subclass.prototype, NON_MIXABLE_OBJECT_PROPERTIES); - return Subclass; - } -} - -/* - * Copy the given properties/methods to the target. - * Return the updated target. - */ -function copyOwnProperties(source, target) { - var ignorePropertyNames = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : []; - - Object.getOwnPropertyNames(source).forEach(function (name) { - if (ignorePropertyNames.indexOf(name) < 0) { - var descriptor = Object.getOwnPropertyDescriptor(source, name); - Object.defineProperty(target, name, descriptor); - } - }); - return target; -} - -},{}],5:[function(require,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; - -var _createSymbol = require('./createSymbol'); - -var _createSymbol2 = _interopRequireDefault(_createSymbol); - -var _toggleClass = require('./toggleClass'); - -var _toggleClass2 = _interopRequireDefault(_toggleClass); - -var _symbols = require('./symbols'); - -var _symbols2 = _interopRequireDefault(_symbols); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } - -function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - -// Symbols for private data members on an element. -var itemsSymbol = (0, _createSymbol2.default)('items'); -var itemInitializedSymbol = (0, _createSymbol2.default)('itemInitialized'); - -/* Exported function extends a base class with ContentItems. */ - -exports.default = function (base) { - - /** - * Mixin which maps content semantics (elements) to list item semantics. - * - * Items differ from element contents in several ways: - * - * * They are often referenced via index. - * * They may have a selection state. - * * It's common to do work to initialize the appearance or state of a new - * item. - * * Auxiliary invisible child elements are filtered out and not counted as - * items. Auxiliary elements include link, script, style, and template - * elements. This filtering ensures that those auxiliary elements can be - * used in markup inside of a list without being treated as list items. - * - * This mixin expects a component to provide a `content` property returning a - * raw set of elements. You can provide that yourself, or use - * [DistributedChildrenContentMixin](DistributedChildrenContentMixin.md). - * - * The most commonly referenced property defined by this mixin is the `items` - * property. To avoid having to do work each time that property is requested, - * this mixin supports an optimized mode. If you invoke the `contentChanged` - * method when the set of items changes, the mixin concludes that you'll take - * care of notifying it of future changes, and turns on the optimization. With - * that on, the mixin saves a reference to the computed set of items, and will - * return that immediately on subsequent calls to the `items` property. If you - * use this mixin in conjunction with - * [DistributedChildrenContentMixin](DistributedChildrenContentMixin.md), the - * `contentChanged` method will be invoked for you when the element's children - * change, turning on the optimization automatically. - */ - var ContentItems = function (_base) { - _inherits(ContentItems, _base); - - function ContentItems() { - _classCallCheck(this, ContentItems); - - return _possibleConstructorReturn(this, (ContentItems.__proto__ || Object.getPrototypeOf(ContentItems)).apply(this, arguments)); - } - - _createClass(ContentItems, [{ - key: 'contentChanged', - value: function contentChanged() { - if (_get(ContentItems.prototype.__proto__ || Object.getPrototypeOf(ContentItems.prototype), 'contentChanged', this)) { - _get(ContentItems.prototype.__proto__ || Object.getPrototypeOf(ContentItems.prototype), 'contentChanged', this).call(this); - } - - // Since we got the contentChanged call, we'll assume we'll be notified if - // the set of items changes later. We turn on memoization of the items - // property by setting our internal property to null (instead of - // undefined). - this[itemsSymbol] = null; - - this[_symbols2.default.itemsChanged](); - } - - /** - * This method is invoked whenever a new item is added to the list. - * - * The default implementation of this method does nothing. You can override - * this to perform per-item initialization. - * - * @param {HTMLElement} item - The item that was added. - */ - - }, { - key: _symbols2.default.itemAdded, - value: function value(item) { - if (_get(ContentItems.prototype.__proto__ || Object.getPrototypeOf(ContentItems.prototype), _symbols2.default.itemAdded, this)) { - _get(ContentItems.prototype.__proto__ || Object.getPrototypeOf(ContentItems.prototype), _symbols2.default.itemAdded, this).call(this, item); - } - } - - /** - * The selection state for a single item has changed. - * - * Invoke this method to signal that the selected state of the indicated item - * has changed. By default, this applies a `selected` CSS class if the item - * is selected, and removed it if not selected. - * - * @param {HTMLElement} item - The item whose selection state has changed. - * @param {boolean} selected - True if the item is selected, false if not. - */ - - }, { - key: _symbols2.default.itemSelected, - value: function value(item, selected) { - if (_get(ContentItems.prototype.__proto__ || Object.getPrototypeOf(ContentItems.prototype), _symbols2.default.itemSelected, this)) { - _get(ContentItems.prototype.__proto__ || Object.getPrototypeOf(ContentItems.prototype), _symbols2.default.itemSelected, this).call(this, item, selected); - } - (0, _toggleClass2.default)(item, 'selected', selected); - } - - /** - * The current set of items in the list. See the top-level documentation for - * mixin for a description of how items differ from plain content. - * - * @type {HTMLElement[]} - */ - - }, { - key: _symbols2.default.itemsChanged, - - - /** - * This method is invoked when the underlying contents change. It is also - * invoked on component initialization – since the items have "changed" from - * being nothing. - */ - value: function value() { - var _this2 = this; - - if (_get(ContentItems.prototype.__proto__ || Object.getPrototypeOf(ContentItems.prototype), _symbols2.default.itemsChanged, this)) { - _get(ContentItems.prototype.__proto__ || Object.getPrototypeOf(ContentItems.prototype), _symbols2.default.itemsChanged, this).call(this); - } - - // Perform per-item initialization. - Array.prototype.forEach.call(this.items, function (item) { - if (!item[itemInitializedSymbol]) { - _this2[_symbols2.default.itemAdded](item); - item[itemInitializedSymbol] = true; - } - }); - - this.dispatchEvent(new CustomEvent('items-changed')); - } - - /** - * Fires when the items in the list change. - * - * @memberof ContentItems - * @event items-changed - */ - - }, { - key: 'items', - get: function get() { - var items = void 0; - if (this[itemsSymbol] == null) { - items = filterAuxiliaryElements(this.content); - // Note: test for *equality* with null; don't treat undefined as a match. - if (this[itemsSymbol] === null) { - // Memoize the set of items. - this[itemsSymbol] = items; - } - } else { - // Return the memoized items. - items = this[itemsSymbol]; - } - return items; - } - }]); - - return ContentItems; - }(base); - - return ContentItems; -}; - -// Return the given elements, filtering out auxiliary elements that aren't -// typically visible. Items which are not elements are returned as is. - - -function filterAuxiliaryElements(items) { - var auxiliaryTags = ['link', 'script', 'style', 'template']; - return [].filter.call(items, function (item) { - return !item.localName || auxiliaryTags.indexOf(item.localName) < 0; - }); -} - -},{"./createSymbol":14,"./symbols":17,"./toggleClass":18}],6:[function(require,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -var _set = function set(object, property, value, receiver) { var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent !== null) { set(parent, property, value, receiver); } } else if ("value" in desc && desc.writable) { desc.value = value; } else { var setter = desc.set; if (setter !== undefined) { setter.call(receiver, value); } } return value; }; - -var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; - -var _microtask = require('./microtask'); - -var _microtask2 = _interopRequireDefault(_microtask); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } - -function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - -/* Exported function extends a base class with DistributedChildrenContent. */ -exports.default = function (base) { - - /** - * Mixin which defines a component's content as its children, expanding any - * nodes distributed to the component's slots. - * - * This also provides notification of changes to a component's content. It - * will invoke a `contentChanged` method when the component is first - * instantiated, and whenever its distributed children change. This is an - * easy way to satisfy the Gold Standard checklist item for monitoring - * [Content Changes](https://github.com/webcomponents/gold-standard/wiki/Content-Changes). - * - * Example: - * - * ``` - * let base = DistributedChildrenContentMixin(DistributedChildrenMixin(HTMLElement)); - * class CountingElement extends base { - * - * constructor() { - * super(); - * let root = this.attachShadow({ mode: 'open' }); - * root.innerHTML = ``; - * } - * - * contentChanged() { - * // Count the component's children, both initially and when changed. - * this.count = this.distributedChildren.length; - * } - * - * } - * ``` - * - * Note that content change detection depends upon the element having at least - * one `slot` element in its shadow subtree. - * - * This mixin is intended for use with the - * [DistributedChildrenMixin](DistributedChildrenMixin.md). See that mixin for - * a discussion of how that works. This DistributedChildrenContentMixin - * provides an easy way of defining the "content" of a component as the - * component's distributed children. That in turn lets mixins like - * [ContentItemsMixin](ContentItemsMixin.md) manipulate the children as list - * items. - */ - var DistributedChildrenContent = function (_base) { - _inherits(DistributedChildrenContent, _base); - - function DistributedChildrenContent() { - _classCallCheck(this, DistributedChildrenContent); - - var _this = _possibleConstructorReturn(this, (DistributedChildrenContent.__proto__ || Object.getPrototypeOf(DistributedChildrenContent)).call(this)); - - if (_this.shadowRoot) { - // Listen to changes on all slots. - var slots = _this.shadowRoot.querySelectorAll('slot'); - slots.forEach(function (slot) { - return slot.addEventListener('slotchange', function (event) { - _this.contentChanged(); - }); - }); - } - - // Make an initial call to contentChanged() so that the component can do - // initialization that it normally does when content changes. - // - // This will invoke contentChanged() handlers in other mixins. In order - // that those mixins have a chance to complete their own initialization, - // we add the contentChanged() call to the microtask queue. - (0, _microtask2.default)(function () { - return _this.contentChanged(); - }); - return _this; - } - - /** - * Invoked when the contents of the component (including distributed - * children) have changed. - * - * This method is also invoked when a component is first instantiated; the - * contents have essentially "changed" from being nothing. This allows the - * component to perform initial processing of its children. - */ - - - _createClass(DistributedChildrenContent, [{ - key: 'contentChanged', - value: function contentChanged() { - if (_get(DistributedChildrenContent.prototype.__proto__ || Object.getPrototypeOf(DistributedChildrenContent.prototype), 'contentChanged', this)) { - _get(DistributedChildrenContent.prototype.__proto__ || Object.getPrototypeOf(DistributedChildrenContent.prototype), 'contentChanged', this).call(this); - } - var event = new CustomEvent('content-changed'); - this.dispatchEvent(event); - } - - /** - * The content of this component, defined to be the flattened array of - * children distributed to the component. - * - * @type {HTMLElement[]} - */ - - }, { - key: 'content', - get: function get() { - var distributedChildren = this.distributedChildren; - if (typeof distributedChildren === 'undefined') { - console.warn('DistributedChildrenContentMixin expects the component to define a "distributedChildren" property.'); - } - return distributedChildren; - }, - set: function set(value) { - if ('content' in base.prototype) { - _set(DistributedChildrenContent.prototype.__proto__ || Object.getPrototypeOf(DistributedChildrenContent.prototype), 'content', value, this); - } - // TODO: Set the children to the given value (which should be an array of - // elements)? - } - - /** - * This event is raised when the component's contents (including distributed - * children) have changed. - * - * @memberof DistributedChildrenContent - * @event content-changed - */ - - }]); - - return DistributedChildrenContent; - }(base); - - return DistributedChildrenContent; -}; - -},{"./microtask":15}],7:[function(require,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } - -function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - -/* Exported function extends a base class with DistributedChildren. */ -exports.default = function (base) { - - /** - * Mixin which defines helpers for accessing a component's distributed - * children as a flattened array or string. - * - * The standard DOM API provides several ways of accessing child content: - * `children`, `childNodes`, and `textContent`. None of these functions are - * Shadow DOM aware. This mixin defines variations of those functions that - * *are* Shadow DOM aware. - * - * Example: you create a component `` that displays a number - * equal to the number of children placed inside that component. If someone - * instantiates your component like: - * - * - *
- *
- *
- *
- * - * Then the component should show "3", because there are three children. To - * calculate the number of children, the component can just calculate - * `this.children.length`. However, suppose someone instantiates your - * component inside one of their own components, and puts a `` element - * inside your component: - * - * - * - * - * - * If your component only looks at `this.children`, it will always see exactly - * one child — the `` element. But the user looking at the page will - * *see* any nodes distributed to that slot. To match what the user sees, your - * component should expand any `` elements it contains. - * - * That is the problem this mixin solves. After applying this mixin, your - * component code has access to `this.distributedChildren`, whose `length` - * will return the total number of all children distributed to your component - * in the composed tree. - * - * Note: The latest Custom Elements API design calls for a new function, - * `getAssignedNodes` that takes an optional `deep` parameter, that will solve - * this problem at the API level. - */ - var DistributedChildren = function (_base) { - _inherits(DistributedChildren, _base); - - function DistributedChildren() { - _classCallCheck(this, DistributedChildren); - - return _possibleConstructorReturn(this, (DistributedChildren.__proto__ || Object.getPrototypeOf(DistributedChildren)).apply(this, arguments)); - } - - _createClass(DistributedChildren, [{ - key: 'distributedChildren', - - - /** - * An in-order collection of distributed children, expanding any slot - * elements. Like the standard children property, this skips text nodes. - * - * @type {HTMLElement[]} - */ - get: function get() { - return expandContentElements(this.children, false); - } - - /** - * An in-order collection of distributed child nodes, expanding any slot - * elements. Like the standard childNodes property, this includes text - * nodes. - * - * @type {Node[]} - */ - - }, { - key: 'distributedChildNodes', - get: function get() { - return expandContentElements(this.childNodes, true); - } - - /** - * The concatenated text content of all distributed child nodes, expanding - * any slot elements. - * - * @type {string} - */ - - }, { - key: 'distributedTextContent', - get: function get() { - var strings = this.distributedChildNodes.map(function (child) { - return child.textContent; - }); - return strings.join(''); - } - }]); - - return DistributedChildren; - }(base); - - return DistributedChildren; -}; - -/* - * Given a array of nodes, return a new array with any content elements expanded - * to the nodes distributed to that content element. This rule is applied - * recursively. - * - * If includeTextNodes is true, text nodes will be included, as in the - * standard childNodes property; by default, this skips text nodes, like the - * standard children property. - */ - - -function expandContentElements(nodes, includeTextNodes) { - var _ref; - - var expanded = Array.prototype.map.call(nodes, function (node) { - // We want to see if the node is an instanceof HTMLSlotELement, but - // that class won't exist if the browser that doesn't support native - // Shadow DOM and if the Shadow DOM polyfill hasn't been loaded. Instead, - // we do a simplistic check to see if the tag name is "slot". - var isSlot = typeof HTMLSlotElement !== 'undefined' ? node instanceof HTMLSlotElement : node.localName === 'slot'; - if (isSlot) { - // Use the nodes assigned to this node instead. - var assignedNodes = node.assignedNodes({ flatten: true }); - return assignedNodes ? expandContentElements(assignedNodes, includeTextNodes) : []; - } else if (node instanceof HTMLElement) { - // Plain element; use as is. - return [node]; - } else if (node instanceof Text && includeTextNodes) { - // Text node. - return [node]; - } else { - // Comment, processing instruction, etc.; skip. - return []; - } - }); - var flattened = (_ref = []).concat.apply(_ref, _toConsumableArray(expanded)); - return flattened; -} - -},{}],8:[function(require,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -var _set = function set(object, property, value, receiver) { var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent !== null) { set(parent, property, value, receiver); } } else if ("value" in desc && desc.writable) { desc.value = value; } else { var setter = desc.set; if (setter !== undefined) { setter.call(receiver, value); } } return value; }; - -var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; - -exports.default = mixin; - -var _createSymbol = require('./createSymbol'); - -var _createSymbol2 = _interopRequireDefault(_createSymbol); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } - -function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - -// Symbols for private data members on an element. -var selectedFractionSymbol = (0, _createSymbol2.default)('selectedFraction'); - -/* Exported function extends a base class with FractionalSelection. */ -function mixin(base) { - - /** - * Adds support for fractional selection: treating a selection as a real - * number that combines an integer portion (an index into a list), and a - * fraction (indicating how far of the way we are to the next or previous - * item). - * - * This is useful in components that support incremental operations during - * dragging and swiping. Example: a carousel component has several items, and the - * currently selected item is item 3. The user begins swiping to the left, - * moving towards selecting item 4. Halfway through this operation, the - * fractional selection value is 3.5. - * - * This value permits communication between mixins like - * [SwipeDirectionMixin](./SwipeDirectionMixin.md) and - * [TrackpadDirectionMixin](./TrackpadDirectionMixin.md), which generate - * fractional selection values, and mixins like - * [SelectionAnimationMixin](./SelectionAnimationMixin.md), which can render - * selection at a fractional value. - */ - var FractionalSelection = function (_base) { - _inherits(FractionalSelection, _base); - - function FractionalSelection() { - _classCallCheck(this, FractionalSelection); - - return _possibleConstructorReturn(this, (FractionalSelection.__proto__ || Object.getPrototypeOf(FractionalSelection)).apply(this, arguments)); - } - - _createClass(FractionalSelection, [{ - key: 'connectedCallback', - value: function connectedCallback() { - if (_get(FractionalSelection.prototype.__proto__ || Object.getPrototypeOf(FractionalSelection.prototype), 'connectedCallback', this)) { - _get(FractionalSelection.prototype.__proto__ || Object.getPrototypeOf(FractionalSelection.prototype), 'connectedCallback', this).call(this); - } - this.selectedFraction = 0; - } - - /** - * A fractional value indicating how far the user has currently advanced to - * the next/previous item. E.g., a `selectedFraction` of 3.5 indicates the - * user is halfway between items 3 and 4. - * - * @type {number} - */ - - }, { - key: 'selectedFraction', - get: function get() { - return this[selectedFractionSymbol]; - }, - set: function set(value) { - this[selectedFractionSymbol] = value; - if ('selectedFraction' in base.prototype) { - _set(FractionalSelection.prototype.__proto__ || Object.getPrototypeOf(FractionalSelection.prototype), 'selectedFraction', value, this); - } - var event = new CustomEvent('selected-fraction-changed'); - this.dispatchEvent(event); - } - }]); - - return FractionalSelection; - }(base); - - return FractionalSelection; -} - -mixin.helpers = { - - /* - * Dampen a selection that goes past the beginning or end of a list. This is - * generally used to produce a visual effect of tension as the user tries to - * go further in a direction that has no more items. - * - * Example: suppose `itemCount` is 5, indicating a list of 5 items. The index of - * the last item is 4. If the `selection` parameter is 4.5, the user is trying - * to go past this last item. When a damping function is applied, the resulting - * value will be less than 4.5 (the actual value will be 4.25). When this - * selection state is rendered, the user will see that, each unit distance the - * drag travels has less and less visible effect. This is perceived as tension. - * - * @param {number} selection - A real number indicating a selection position - * @param {number} itemCount - An integer for the number of items in the list - * @returns {number} A real number representing the damped selection value. - */ - dampedSelection: function dampedSelection(selection, itemCount) { - var bound = itemCount - 1; - var damped = void 0; - if (selection < 0) { - // Trying to go past beginning of list. Apply tension from the left edge. - damped = -mixin.helpers.damping(-selection); - } else if (selection >= bound) { - // Trying to go past end of list. Apply tension from the right edge. - damped = bound + mixin.helpers.damping(selection - bound); - } else { - // No damping required. - damped = selection; - } - return damped; - }, - - - /* - * Calculate damping as a function of the distance past the minimum/maximum - * values. - * - * We want to asymptotically approach an absolute minimum of 1 unit - * below/above the actual minimum/maximum. This requires calculating a - * hyperbolic function. - * - * See http://www.wolframalpha.com/input/?i=y+%3D+-1%2F%28x%2B1%29+%2B+1 - * for the one we use. The only portion of that function we care about is when - * x is zero or greater. An important consideration is that the curve be - * tangent to the diagonal line x=y at (0, 0). This ensures smooth continuity - * with the normal drag behavior, in which the visible sliding is linear with - * the distance the touchpoint has been dragged. - */ - damping: function damping(x) { - var y = -1 / (x + 1) + 1; - return y; - }, - - - /* - * Return the current fractional selection value for the given element. - * - * This simply adds the element's `selectedIndex` and `selectedFraction` - * properties. - * - * @param {HTMLElement} element - An element that supports selection - */ - elementSelection: function elementSelection(element) { - var selectedIndex = element.selectedIndex; - if (selectedIndex < 0) { - // No selection - return; - } - var selectedFraction = element.selectedFraction || 0; - return selectedIndex + selectedFraction; - }, - - - /* - * Breaks a fractional selection into its integer and fractional parts. - * - * Example: if passed 3.5, this returns { index: 3, fraction: 5 }. - * - * @param {number} selection – A real number representing a selection point - * @returns {object} - An object with an `index` property holding the - * selection's integer component, and a `fraction` property holding the - * selection's fractional component. - */ - selectionParts: function selectionParts(selection) { - // Stupid IE doesn't have Math.trunc. - // const index = Math.trunc(selection); - var index = selection < 0 ? Math.ceil(selection) : Math.floor(selection); - var fraction = selection - index; - return { index: index, fraction: fraction }; - }, - - - /* - * Returns a fractional selection point after accounting for wrapping, ensuring - * that the integer portion of the selection stays between 0 and `itemCount`-1. - * That is, the integer portion will always be a valid index into the list. - * - * Example of wrapping past the end of the list: if `selection` is 5.5 and - * `itemCount` is 5, this returns 0.5. Example of wrapping past the beginning of - * the list: if `selection` is 0.5 and `itemCount` is 5, this returns 4.5. - * - * @param {number} selection - A real number representing a selection point - * @param {number} itemCount - The number of items in the list - * @returns {number} - The result of wrapping the selection point - */ - wrappedSelection: function wrappedSelection(selection, itemCount) { - // Handles possibility of negative mod. - // See http://stackoverflow.com/a/18618250/76472 - return (selection % itemCount + itemCount) % itemCount; - }, - - - /* - * Return the parts of a selection, first wrapping if necessary. - * - * @param {number} selection – A real number representing a selection point - * @param {number} itemCount - The number of items in the list - * @param {boolean} wrap – True if the selection should wrap to stay within the - * list - * @returns {object} – The parts of the selection, using the same format as - * `selectionParts`. - */ - wrappedSelectionParts: function wrappedSelectionParts(selection, itemCount, wrap) { - if (wrap) { - selection = mixin.helpers.wrappedSelection(selection, itemCount); - } - return mixin.helpers.selectionParts(selection); - } -}; - -},{"./createSymbol":14}],9:[function(require,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -var _set = function set(object, property, value, receiver) { var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent !== null) { set(parent, property, value, receiver); } } else if ("value" in desc && desc.writable) { desc.value = value; } else { var setter = desc.set; if (setter !== undefined) { setter.call(receiver, value); } } return value; }; - -var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; - -exports.default = mixin; - -var _createSymbol = require('./createSymbol'); - -var _createSymbol2 = _interopRequireDefault(_createSymbol); - -var _FractionalSelectionMixin = require('./FractionalSelectionMixin'); - -var _FractionalSelectionMixin2 = _interopRequireDefault(_FractionalSelectionMixin); - -var _symbols = require('./symbols'); - -var _symbols2 = _interopRequireDefault(_symbols); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } - -function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - -// Symbols for private data members on an element. -var animationSymbol = (0, _createSymbol2.default)('animation'); -var draggingSymbol = (0, _createSymbol2.default)('dragging'); -var lastAnimationSymbol = (0, _createSymbol2.default)('lastAnimation'); -var playingAnimationSymbol = (0, _createSymbol2.default)('animatingSelection'); -var previousSelectionSymbol = (0, _createSymbol2.default)('previousSelection'); -var selectionAnimationDurationSymbol = (0, _createSymbol2.default)('selectionAnimationDuration'); -var selectionAnimationEffectSymbol = (0, _createSymbol2.default)('selectionAnimationEffect'); -var selectionAnimationKeyframesSymbol = (0, _createSymbol2.default)('selectionAnimationKeyframes'); -var resetAnimationsOnNextRenderSymbol = (0, _createSymbol2.default)('resetAnimationsOnNextRender'); - -/* Exported function extends a base class with SelectionAnimation. */ -function mixin(base) { - - /** - * Mixin which uses animation to show transitions between selection states. - * - * This mixin can be used by components that want to provide visible - * animations when changing the selection. For example, a carousel component - * may want to define a sliding animation effect shown when moving between - * items. - * - * The animation is defined by a `selectionAnimationKeyframes` property; see - * that property for details on how to define these keyframes. This animation - * will be used in two ways. First, when moving strictly between items, the - * animation will play smoothly to show the selection changing. Second, the - * animation can be used to render the selection at a fixed point in the - * transition between states. E.g., if the user pauses halfway through - * dragging an element using [SwipeDirectionMixin](SwipeDirectionMixin.md) - * or [TrackpadDirectionMixin](TrackpadDirectionMixin.md)s, then the selection - * animation will be shown at the point exactly halfway through. - * - * This mixin expects a component to provide an `items` array of all elements - * in the list, which can be provided via - * [ContentItemsMixin](ContentItemsMixin.md). This mixin also expects - * `selectedIndex` and `selectedItem` properties, which can be provided via - * [SingleSelectionMixin](SingleSelectionMixin.md). - * - * This mixin supports a `selectionWraps` property. When true, the user can - * navigate forward from the last item in the list and wrap around to the - * first item, or navigate backward from the first item and wrap around to the - * last item. - * - * This mixin uses the Web Animations API. For use on browsers which - * do not support that API natively, you will need to load the - * [Web Animations polyfill](https://github.com/web-animations/web-animations-js). - */ - var SelectionAnimation = function (_base) { - _inherits(SelectionAnimation, _base); - - function SelectionAnimation() { - _classCallCheck(this, SelectionAnimation); - - // Set defaults. - var _this = _possibleConstructorReturn(this, (SelectionAnimation.__proto__ || Object.getPrototypeOf(SelectionAnimation)).call(this)); - - if (typeof _this.selectionAnimationDuration === 'undefined') { - _this.selectionAnimationDuration = _this[_symbols2.default.defaults].selectionAnimationDuration; - } - if (typeof _this.selectionAnimationEffect === 'undefined' && _this.selectionAnimationKeyframes == null) { - _this.selectionAnimationEffect = _this[_symbols2.default.defaults].selectionAnimationEffect; - } - - _this[_symbols2.default.dragging] = false; - return _this; - } - - _createClass(SelectionAnimation, [{ - key: _symbols2.default.itemAdded, - value: function value(item) { - // We mark new items in the list as explicitly visible to ARIA. Otherwise, - // when an item isn't visible on the screen, ARIA will assume the item is - // of no interest to the user, and leave it out of the accessibility tree. - // If the list contains 10 items, but only 3 are visible, a screen reader - // might then announce the list only has 3 items. To ensure that screen - // readers and other assistive technologies announce the correct total - // number of items, we explicitly mark all items as not hidden. This will - // expose them all in the accessibility tree, even the items which are - // currently not rendered. - // - // TODO: Generally speaking, this entire mixin assumes that the user can - // navigate through all items in a list. But an app could style an item as - // display:none or visibility:hidden because the user is not allowed to - // interact with that item at the moment. Support for this scenario should - // be added. This would entail changing all locations where a mixin - // function is counting items, iterating over the (visible) items, and - // showing or hiding items. Among other things, the code below to make - // items visible to ARIA would need to discriminate between items which - // are invisible because of animation state, or invisible because the user - // shouldn't interact with them. - item.setAttribute('aria-hidden', false); - } - }, { - key: _symbols2.default.itemsChanged, - value: function value() { - if (_get(SelectionAnimation.prototype.__proto__ || Object.getPrototypeOf(SelectionAnimation.prototype), _symbols2.default.itemsChanged, this)) { - _get(SelectionAnimation.prototype.__proto__ || Object.getPrototypeOf(SelectionAnimation.prototype), _symbols2.default.itemsChanged, this).call(this); - } - - _resetAnimations(this); - - // TODO: Also reset our notion of the last rendered selection? This comes - // up when a DOM removal causes the selected item to change position. - // this[previousSelectionSymbol] = null; - - renderSelection(this); - } - }, { - key: 'resetAnimations', - value: function resetAnimations() { - _resetAnimations(this); - } - - /** - * A fractional value indicating how far the user has currently advanced to - * the next/previous item. E.g., a `selectedFraction` of 3.5 indicates the - * user is halfway between items 3 and 4. - * - * For more details, see [FractionalSelectionMixin](FractionalSelectionMixin.md) - * mixin. - * - * @type {number} - */ - - }, { - key: _symbols2.default.defaults, - get: function get() { - var defaults = _get(SelectionAnimation.prototype.__proto__ || Object.getPrototypeOf(SelectionAnimation.prototype), _symbols2.default.defaults, this) || {}; - defaults.selectionAnimationDuration = 250; - defaults.selectionAnimationEffect = 'slide'; - return defaults; - } - - /* - * Provide backing for the dragging property. - * Also, when a drag begins, reset the animations. - */ - - }, { - key: _symbols2.default.dragging, - get: function get() { - return this[draggingSymbol]; - }, - set: function set(value) { - var previousValue = this[_symbols2.default.dragging]; - this[draggingSymbol] = value; - if (_symbols2.default.dragging in base.prototype) { - _set(SelectionAnimation.prototype.__proto__ || Object.getPrototypeOf(SelectionAnimation.prototype), _symbols2.default.dragging, value, this); - } - if (value && !previousValue) { - // Have begun a drag. - this[resetAnimationsOnNextRenderSymbol] = true; - } - } - }, { - key: 'selectedFraction', - get: function get() { - return _get(SelectionAnimation.prototype.__proto__ || Object.getPrototypeOf(SelectionAnimation.prototype), 'selectedFraction', this) || 0; - }, - set: function set(value) { - if ('selectedFraction' in base.prototype) { - _set(SelectionAnimation.prototype.__proto__ || Object.getPrototypeOf(SelectionAnimation.prototype), 'selectedFraction', value, this); - } - renderSelection(this, this.selectedIndex, value); - } - }, { - key: 'selectedIndex', - get: function get() { - return _get(SelectionAnimation.prototype.__proto__ || Object.getPrototypeOf(SelectionAnimation.prototype), 'selectedIndex', this); - }, - set: function set(index) { - if ('selectedIndex' in base.prototype) { - _set(SelectionAnimation.prototype.__proto__ || Object.getPrototypeOf(SelectionAnimation.prototype), 'selectedIndex', index, this); - } - renderSelection(this, index, 0); - } - - /** - * The duration of a selection animation in milliseconds. - * - * This measures the amount of time required for a selection animation to - * complete. This number remains constant, even if the number of items being - * animated increases. - * - * The default value is 250 milliseconds (a quarter a second). - * - * @type {number} - * @default 250 - */ - - }, { - key: 'selectionAnimationDuration', - get: function get() { - return this[selectionAnimationDurationSymbol]; - }, - set: function set(value) { - this[selectionAnimationDurationSymbol] = value; - if ('selectionAnimationDuration' in base.prototype) { - _set(SelectionAnimation.prototype.__proto__ || Object.getPrototypeOf(SelectionAnimation.prototype), 'selectionAnimationDuration', value, this); - } - } - - /** - * The name of a standard selection animation effect. - * - * This is a shorthand for setting the `selectionAnimationKeyframes` - * property to standard keyframes. Supported string values: - * - * * "crossfade" - * * "reveal" - * * "revealWithFade" - * * "showAdjacent" - * * "slide" - * * "slideWithGap" - * - * @type {string} - * @default "slide" - */ - - }, { - key: 'selectionAnimationEffect', - get: function get() { - return this[selectionAnimationEffectSymbol]; - }, - set: function set(value) { - this[selectionAnimationEffectSymbol] = value; - if ('selectionAnimationEffect' in base.prototype) { - _set(SelectionAnimation.prototype.__proto__ || Object.getPrototypeOf(SelectionAnimation.prototype), 'selectionAnimationEffect', value, this); - } - this.selectionAnimationKeyframes = mixin.standardEffectKeyframes[value]; - } - - /** - * The keyframes that define an animation that plays for an item when moving - * forward in the sequence. - * - * This is an array of CSS rules that will be applied. These are used as - * [keyframes](http://w3c.github.io/web-animations/#keyframes-section) - * to animate the item with the - * [Web Animations API](https://developer.mozilla.org/en-US/docs/Web/API/animation). - * - * The animation represents the state of the next item as it moves from - * completely unselected (offstage, usually right), to selected (center - * stage), to completely unselected (offstage, usually left). The center time - * of the animation should correspond to the item's quiscent selected state, - * typically in the center of the stage and at the item's largest size. - * - * The default forward animation is a smooth slide at full size from right to - * left. - * - * When moving the selection backward, this animation is played in reverse. - * - * @type {cssRules[]} - */ - - }, { - key: 'selectionAnimationKeyframes', - get: function get() { - // Standard animation slides left/right, keeps adjacent items out of view. - return this[selectionAnimationKeyframesSymbol]; - }, - set: function set(value) { - this[selectionAnimationKeyframesSymbol] = value; - if ('selectionAnimationKeyframes' in base.prototype) { - _set(SelectionAnimation.prototype.__proto__ || Object.getPrototypeOf(SelectionAnimation.prototype), 'selectionAnimationKeyframes', value, this); - } - _resetAnimations(this); - renderSelection(this); - } - }, { - key: 'selectionWraps', - get: function get() { - return _get(SelectionAnimation.prototype.__proto__ || Object.getPrototypeOf(SelectionAnimation.prototype), 'selectionWraps', this); - }, - set: function set(value) { - if ('selectionWraps' in base.prototype) { - _set(SelectionAnimation.prototype.__proto__ || Object.getPrototypeOf(SelectionAnimation.prototype), 'selectionWraps', value, this); - } - _resetAnimations(this); - renderSelection(this); - } - }]); - - return SelectionAnimation; - }(base); - - return SelectionAnimation; -} - -// We expose helpers on the mixin function that we want to be able to unit test. -// Since these are on the function, not on the class emitted by the function, -// they don't end up getting exposed on actual element instances. -mixin.helpers = { - - /* - * Calculate the animation fractions for an element's items at the given - * selection point. This is used when rendering the element's selection state - * instantaneously. - * - * This function considers the selectedIndex parameter, which can be a whole - * or fractional number, and determines which items will be visible at that - * index. This function then calculates a corresponding animation fraction: a - * number between 0 and 1 indicating how far through the selection animation - * an item should be shown, or null if the item should not be visible at that - * selection index. These fractions are returned as an array, where the - * animation fraction at position N corresponds to how item N should be shown. - */ - animationFractionsForSelection: function animationFractionsForSelection(element, selection) { - - var items = element.items; - if (!items) { - return; - } - - var itemCount = items.length; - var selectionWraps = element.selectionWraps; - - return items.map(function (item, itemIndex) { - // How many steps from the selection point to this item? - var steps = stepsToIndex(itemCount, selectionWraps, selection, itemIndex); - // To convert steps to animation fraction: - // steps animation fraction - // 1 0 (stage right) - // 0 0.5 (center stage) - // -1 1 (stage left) - var animationFraction = (1 - steps) / 2; - return animationFraction >= 0 && animationFraction <= 1 ? animationFraction : null; // Outside animation range - }); - }, - - - /* - * Calculate the animation timings that should be used to smoothly animate the - * element's items from one selection state to another. - * - * This returns an array of timings, where the timing at position N should be - * used to animate item N. If an item's timing is null, then that item should - * not take place in the animation, and should be hidden instead. - */ - effectTimingsForSelectionAnimation: function effectTimingsForSelectionAnimation(element, fromSelection, toSelection) { - - var items = element.items; - if (!items) { - return; - } - var itemCount = items.length; - var selectionWraps = element.selectionWraps; - var toIndex = _FractionalSelectionMixin2.default.helpers.wrappedSelectionParts(toSelection, itemCount, selectionWraps).index; - var totalSteps = stepsToIndex(itemCount, selectionWraps, fromSelection, toSelection); - var direction = totalSteps >= 0 ? 'normal' : 'reverse'; - var fill = 'both'; - var totalDuration = element.selectionAnimationDuration; - var stepDuration = totalSteps !== 0 ? totalDuration * 2 / Math.ceil(Math.abs(totalSteps)) : 0; // No steps required, animation will be instantenous. - - var timings = items.map(function (item, itemIndex) { - var steps = stepsToIndex(itemCount, selectionWraps, itemIndex, toSelection); - // If we include this item in the staggered sequence of animations we're - // creating, where would the item appear in the sequence? - var positionInSequence = totalSteps - steps; - if (totalSteps < 0) { - positionInSequence = -positionInSequence; - } - // So, is this item really included in the sequence? - if (Math.ceil(positionInSequence) >= 0 && positionInSequence <= Math.abs(totalSteps)) { - // Note that delay for first item will be negative. That will cause - // the animation to start halfway through, which is what we want. - var delay = stepDuration * (positionInSequence - 1) / 2; - var endDelay = itemIndex === toIndex ? -stepDuration / 2 : // Stop halfway through. - 0; // Play animation until end. - return { duration: stepDuration, direction: direction, fill: fill, delay: delay, endDelay: endDelay }; - } else { - return null; - } - }); - - return timings; - } -}; - -// Keyframes for standard selection animation effects. -mixin.standardEffectKeyframes = { - - // Simple crossfade - crossfade: [{ opacity: 0 }, { opacity: 1 }, { opacity: 0 }], - - // Reveal, as if sliding the top card off a deck of cards - reveal: [{ transform: 'translateX(0%)', zIndex: 0 }, { transform: 'translateX(0%)', zIndex: 1 }, { transform: 'translateX(-100%)', zIndex: 2 }], - - // Google Photos-style reveal-with-fade animation - revealWithFade: [{ transform: 'translateX(0%) scale(0.75)', opacity: 0, zIndex: 0 }, { transform: 'translateX(0%) scale(1.0)', opacity: 1, zIndex: 1 }, { transform: 'translateX(-100%) scale(1.0)', opacity: 1, zIndex: 2 }], - - // Carousel variant with a bit of off-stage elements showing - showAdjacent: [{ transform: 'translateX(78%) scale(0.7)', zIndex: 0 }, { transform: 'translateX(0%) scale(0.82)', zIndex: 1 }, { transform: 'translateX(-78%) scale(0.7)', zIndex: 0 }], - - // Simple slide - slide: [{ transform: 'translateX(100%)' }, { transform: 'translateX(-100%)' }], - - // Slide, with a gap between - slideWithGap: [{ transform: 'translateX(110%)' }, { transform: 'translateX(-110%)' }] - -}; - -/* - * Smoothly animate the selection between the indicated "from" and "to" - * indices. The former can be a fraction, e.g., when the user releases a finger - * to complete a touch drag, and the selection will snap to the closest whole - * index. - */ -function animateSelection(element, fromSelection, toSelection) { - - _resetAnimations(element); - - // Calculate the animation timings. - var items = element.items; - var keyframes = element.selectionAnimationKeyframes; - element[playingAnimationSymbol] = true; - var timings = mixin.helpers.effectTimingsForSelectionAnimation(element, fromSelection, toSelection); - - // Figure out which item will be the one *after* the one we're selecting. - var itemCount = items.length; - var selectionWraps = element.selectionWraps; - var selectionIndex = _FractionalSelectionMixin2.default.helpers.selectionParts(toSelection, itemCount, selectionWraps).index; - var totalSteps = stepsToIndex(itemCount, selectionWraps, fromSelection, toSelection); - var forward = totalSteps >= 0; - var nextUpIndex = selectionIndex + (forward ? 1 : -1); - if (selectionWraps) { - nextUpIndex = _FractionalSelectionMixin2.default.helpers.wrappedSelection(nextUpIndex, itemCount); - } else if (!isItemIndexInBounds(element, nextUpIndex)) { - nextUpIndex = null; // At start/end of list; don't have a next item to show. - } - - // Play the animations using those timings. - var lastAnimationDetails = void 0; - timings.forEach(function (timing, index) { - var item = items[index]; - if (timing) { - showItem(item, true); - var animation = item.animate(keyframes, timing); - element[animationSymbol][index] = animation; - if (index === nextUpIndex) { - // This item will be animated, so will already be in the desired state - // after the animation completes. - nextUpIndex = null; - } - if (timing.endDelay !== 0) { - // This is the animation for the item that will be left selected. - // We want to clean up when this animation completes. - lastAnimationDetails = { animation: animation, index: index, timing: timing, forward: forward }; - } - } else { - // This item doesn't participate in the animation. - showItem(item, false); - } - }); - - if (lastAnimationDetails != null) { - // Arrange for clean-up work to be performed. - lastAnimationDetails.nextUpIndex = nextUpIndex; - lastAnimationDetails.animation.onfinish = function (event) { - return selectionAnimationFinished(element, lastAnimationDetails); - }; - element[lastAnimationSymbol] = lastAnimationDetails.animation; - } else { - // Shouldn't happen -- we should always have at least one animation. - element[playingAnimationSymbol] = false; - } -} - -function getAnimationForItemIndex(element, index) { - if (element[animationSymbol] == null) { - // Not ready yet; - return null; - } - var animation = element[animationSymbol][index]; - if (!animation) { - var item = element.items[index]; - animation = item.animate(element.selectionAnimationKeyframes, { - duration: element.selectionAnimationDuration, - fill: 'both' - }); - animation.pause(); - element[animationSymbol][index] = animation; - } - return animation; -} - -function isItemIndexInBounds(element, index) { - return index >= 0 && element.items && index < element.items.length; -} - -/* - * Render the selection state of the element. - * - * This can be used to re-render a previous selection state (if the - * selectedIndex param is omitted), render the selection instantly at a given - * whole or fractional selection index, or animate to a given selection index. - * - * There are several distinct scenarios we need to cover: - * - * 1. Initial positioning, or repositioning after changing a property like - * selectionAnimationKeyframes that affects rendering. - * 2. Animate on selectedIndex change. This should override any animation/swipe - * already in progress. - * 3. Instantly render the current position of a drag operation in progress. - * 4. Complete a drag operation. If the drag wasn't far enough to affect - * selection, we'll just be restoring the selectedFraction to 0. - * - * If the list does not wrap, any selection position outside the list's bounds - * will be damped to produce a visual effect of tension. - */ -function renderSelection(element) { - var selectedIndex = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : element.selectedIndex; - var selectedFraction = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : element.selectedFraction; - - var itemCount = element.items ? element.items.length : 0; - if (itemCount === 0) { - // Nothing to render. - return; - } - if (selectedIndex < 0) { - // TODO: Handle no selection. - return; - } - var selection = selectedIndex + selectedFraction; - if (element.selectionWraps) { - // Apply wrapping to ensure consistent representation of selection. - selection = _FractionalSelectionMixin2.default.helpers.wrappedSelection(selection, itemCount); - } else { - // Apply damping if necessary. - selection = _FractionalSelectionMixin2.default.helpers.dampedSelection(selection, itemCount); - } - var previousSelection = element[previousSelectionSymbol]; - // TODO: If an item changes position in the DOM, we end up animating from - // its old index to its new index, but we really don't want to animate at all. - if (!element[_symbols2.default.dragging] && previousSelection != null && previousSelection !== selection) { - // Animate selection from previous state to new state. - animateSelection(element, previousSelection, selection); - } else if (selectedFraction === 0 && element[playingAnimationSymbol]) { - // Already in process of animating to fraction 0. During that process, - // ignore subsequent attempts to renderSelection to fraction 0. - return; - } else { - // Render current selection state instantly. - renderSelectionInstantly(element, selection); - } - element[previousSelectionSymbol] = selection; -} - -/* - * Instantly render (don't animate) the element's items at the given whole or - * fractional selection index. - */ -function renderSelectionInstantly(element, toSelection) { - if (element[resetAnimationsOnNextRenderSymbol]) { - _resetAnimations(element); - element[resetAnimationsOnNextRenderSymbol] = false; - } - var animationFractions = mixin.helpers.animationFractionsForSelection(element, toSelection); - animationFractions.map(function (animationFraction, index) { - var item = element.items[index]; - if (animationFraction != null) { - showItem(item, true); - setAnimationFraction(element, index, animationFraction); - } else { - showItem(item, false); - } - }); -} - -/* - * We maintain an array containing an animation per item. This is used for two - * reasons: - * - * * During a drag operation, we want to be able to reuse animations between - * drag updates. - * * When a selection animation completes, we need to be able to leave the - * visibile items in a paused state. Later, we'll want to be able to clean up - * those animations. - * - * Note that this array is sparse: it will only hold up from 0–3 animations at - * any given point. - */ -function _resetAnimations(element) { - var animations = element[animationSymbol]; - if (animations) { - // Cancel existing animations to remove the effects they're applying. - animations.forEach(function (animation, index) { - if (animation) { - animation.cancel(); - animations[index] = null; - } - }); - } - var itemCount = element.items ? element.items.length : 0; - if (!animations || animations.length !== itemCount) { - // Haven't animated before with this number of items; (re)create array. - element[animationSymbol] = new Array(itemCount); - } -} - -/* - * The last animation in our selection animation has completed. Clean up. - */ -function selectionAnimationFinished(element, details) { - - // When the last animation completes, show the next item in the direction - // we're going. Waiting to that until this point is a bit of a hack to avoid - // having a next item that's higher in the natural z-order obscure other items - // during animation. - var nextUpIndex = details.nextUpIndex; - if (nextUpIndex != null) { - if (element[animationSymbol][nextUpIndex]) { - // Cancel existing selection animation so we can construct a new one. - element[animationSymbol][nextUpIndex].cancel(); - element[animationSymbol][nextUpIndex] = null; - } - var animationFraction = details.forward ? 0 : 1; - setAnimationFraction(element, nextUpIndex, animationFraction); - showItem(element.items[nextUpIndex], true); - } - - element[lastAnimationSymbol].onfinish = null; - element[playingAnimationSymbol] = false; -} - -/* - * Pause the indicated animation and have it show the animation at the given - * fraction (between 0 and 1) of the way through the animation. - */ -function setAnimationFraction(element, itemIndex, fraction) { - var animation = getAnimationForItemIndex(element, itemIndex); - if (animation) { - var duration = element.selectionAnimationDuration; - if (duration) { - animation.currentTime = fraction * duration; - } - } -} - -function showItem(item, flag) { - item.style.visibility = flag ? 'visible' : 'hidden'; -} - -/* - * Figure out how many steps it will take to go from fromSelection to - * toSelection. To go from item 3 to item 4 is one step. - * - * If wrapping is allowed, then going from the last item to the first will take - * one step (forward), and going from the first item to the last will take one - * step (backward). - */ -function stepsToIndex(length, allowWrap, fromSelection, toSelection) { - var steps = toSelection - fromSelection; - // Wrapping only kicks in when list has more than 1 item. - if (allowWrap && length > 1) { - var wrapSteps = length - Math.abs(steps); - if (wrapSteps <= 1) { - // Special case - steps = steps < 0 ? wrapSteps : // Wrap forward from last item to first. - -wrapSteps; // Wrap backward from first item to last. - } - } - return steps; -} - -},{"./FractionalSelectionMixin":8,"./createSymbol":14,"./symbols":17}],10:[function(require,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -var _set = function set(object, property, value, receiver) { var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent !== null) { set(parent, property, value, receiver); } } else if ("value" in desc && desc.writable) { desc.value = value; } else { var setter = desc.set; if (setter !== undefined) { setter.call(receiver, value); } } return value; }; - -var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; - -var _symbols = require('./symbols'); - -var _symbols2 = _interopRequireDefault(_symbols); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } - -function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - -// Used to assign unique IDs to item elements without IDs. -var idCount = 0; - -/* Exported function extends a base class with SelectionAriaActive. */ - -exports.default = function (base) { - - /** - * Mixin which treats the selected item in a list as the active item in ARIA - * accessibility terms. - * - * Handling ARIA selection state properly is actually quite complex: - * - * * The items in the list need to be indicated as possible items via an ARIA - * `role` attribute value such as "option". - * * The selected item need to be marked as selected by setting the item's - * `aria-selected` attribute to true *and* the other items need be marked as - * *not* selected by setting `aria-selected` to false. - * * The outermost element with the keyboard focus needs to have attributes - * set on it so that the selection is knowable at the list level via the - * `aria-activedescendant` attribute. - * * Use of `aria-activedescendant` in turn requires that all items in the - * list have ID attributes assigned to them. - * - * This mixin tries to address all of the above requirements. To that end, - * this mixin will assign generated IDs to any item that doesn't already have - * an ID. - * - * ARIA relies on elements to provide `role` attributes. This mixin will apply - * a default role of "listbox" on the outer list if it doesn't already have an - * explicit role. Similarly, this mixin will apply a default role of "option" - * to any list item that does not already have a role specified. - * - * This mixin expects a set of members that manage the state of the selection: - * `[symbols.itemSelected]`, `itemAdded`, and `selectedIndex`. You can - * supply these yourself, or do so via - * [SingleSelectionMixin](SingleSelectionMixin.md). - */ - var SelectionAriaActive = function (_base) { - _inherits(SelectionAriaActive, _base); - - function SelectionAriaActive() { - _classCallCheck(this, SelectionAriaActive); - - return _possibleConstructorReturn(this, (SelectionAriaActive.__proto__ || Object.getPrototypeOf(SelectionAriaActive)).apply(this, arguments)); - } - - _createClass(SelectionAriaActive, [{ - key: 'connectedCallback', - value: function connectedCallback() { - if (_get(SelectionAriaActive.prototype.__proto__ || Object.getPrototypeOf(SelectionAriaActive.prototype), 'connectedCallback', this)) { - _get(SelectionAriaActive.prototype.__proto__ || Object.getPrototypeOf(SelectionAriaActive.prototype), 'connectedCallback', this).call(this); - } - // Set default ARIA role. - if (this.getAttribute('role') == null && this[_symbols2.default.defaults].role) { - this.setAttribute('role', this[_symbols2.default.defaults].role); - } - } - }, { - key: _symbols2.default.itemAdded, - value: function value(item) { - if (_get(SelectionAriaActive.prototype.__proto__ || Object.getPrototypeOf(SelectionAriaActive.prototype), _symbols2.default.itemAdded, this)) { - _get(SelectionAriaActive.prototype.__proto__ || Object.getPrototypeOf(SelectionAriaActive.prototype), _symbols2.default.itemAdded, this).call(this, item); - } - - if (!item.getAttribute('role')) { - // Assign a default ARIA role. - item.setAttribute('role', 'option'); - } - - // Ensure each item has an ID so we can set aria-activedescendant on the - // overall list whenever the selection changes. - // - // The ID will take the form of a base ID plus a unique integer. The base - // ID will be incorporate the component's own ID. E.g., if a component has - // ID "foo", then its items will have IDs that look like "_fooOption1". If - // the compnent has no ID itself, its items will get IDs that look like - // "_option1". Item IDs are prefixed with an underscore to differentiate - // them from manually-assigned IDs, and to minimize the potential for ID - // conflicts. - if (!item.id) { - var baseId = this.id ? "_" + this.id + "Option" : "_option"; - item.id = baseId + idCount++; - } - } - }, { - key: _symbols2.default.itemSelected, - value: function value(item, selected) { - if (_get(SelectionAriaActive.prototype.__proto__ || Object.getPrototypeOf(SelectionAriaActive.prototype), _symbols2.default.itemSelected, this)) { - _get(SelectionAriaActive.prototype.__proto__ || Object.getPrototypeOf(SelectionAriaActive.prototype), _symbols2.default.itemSelected, this).call(this, item, selected); - } - item.setAttribute('aria-selected', selected); - var itemId = item.id; - if (itemId && selected) { - this.setAttribute('aria-activedescendant', itemId); - } - } - }, { - key: _symbols2.default.defaults, - get: function get() { - var defaults = _get(SelectionAriaActive.prototype.__proto__ || Object.getPrototypeOf(SelectionAriaActive.prototype), _symbols2.default.defaults, this) || {}; - defaults.role = 'listbox'; - return defaults; - } - }, { - key: 'selectedItem', - get: function get() { - return _get(SelectionAriaActive.prototype.__proto__ || Object.getPrototypeOf(SelectionAriaActive.prototype), 'selectedItem', this); - }, - set: function set(item) { - if ('selectedItem' in base.prototype) { - _set(SelectionAriaActive.prototype.__proto__ || Object.getPrototypeOf(SelectionAriaActive.prototype), 'selectedItem', item, this); - } - if (item == null) { - // Selection was removed. - this.removeAttribute('aria-activedescendant'); - } - } - }]); - - return SelectionAriaActive; - }(base); - - return SelectionAriaActive; -}; - -},{"./symbols":17}],11:[function(require,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } - -function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - -/* Exported function extends a base class with ShadowElementReferences. */ -exports.default = function (base) { - - /** - * Mixin to create references to elements in a component's Shadow DOM subtree. - * - * This adds a member on the component called `this.$` that can be used to - * reference shadow elements with IDs. E.g., if component's shadow contains an - * element `