diff --git a/.eslintrc b/.eslintrc index fa3171c..cabc09e 100755 --- a/.eslintrc +++ b/.eslintrc @@ -9,7 +9,7 @@ }, "rules": { "new-cap": [0], - "max-params": [2, 4], + "max-params": [2, 5], "require-jsdoc": [2, { "require": { "FunctionDeclaration": true, diff --git a/README.md b/README.md index f46a69b..8b24725 100755 --- a/README.md +++ b/README.md @@ -292,11 +292,16 @@ A dropdown menu containing multiple options. --- -#### Color +#### Color Picker **Manipulator:** [`color`](#color) -A color picker containing the 64 supported colors on Basalt and Chalk. +A color picker that allows users to choose a color from the ones that are compatible with their Pebble smartwatch. +The color picker will automatically show a different layout depending on the watch connected: + + - Aplite (Firmware 2.x) - Black and white + - Aplite (Firmware 3.x) - Black and white. Will also include gray (`#AAAAAA`) if `allowGray` is set to `true` + - Basalt/chalk - The 64 colors compatible with color Pebble smartwatches. ##### Properties @@ -306,9 +311,11 @@ A color picker containing the 64 supported colors on Basalt and Chalk. | id | string (unique) | Set this to a unique string to allow this item to be looked up using `Clay.getItemsById()` in your [custom function](#custom-function). | | appKey | string (unique) | The AppMessage key matching the `appKey` item defined in your `appinfo.json`. Set this to a unique string to allow this item to be looked up using `Clay.getItemsByAppKey()` in your custom function. You must set this if you wish for the value of this item to be persisted after the user closes the config page. | | label | string | The label that should appear next to this item. | -| defaultValue | string OR int | The default color. Always use the uncorrected value even if `sunlight` is true. The component will do the conversion internally. | +| defaultValue | string OR int | The default color. One of the [64 colors](https://developer.pebble.com/guides/tools-and-resources/color-picker/) compatible with Pebble smartwatches. Always use the uncorrected value even if `sunlight` is true. The component will do the conversion internally. | | description | string | Optional sub-text to include below the component | | sunlight | boolean | Use the color-corrected sunlight color palette if `true`, else the uncorrected version. Defaults to `true` if not specified. | +| layout | string OR array | Optional. Use a custom layout for the color picker. Defaults to automatically choosing the most appropriate layout for the connected watch. The layout is represented by a two dimensional array. Use `false` to insert blank spaces. You may also use one of the preset layouts by setting `layout` to: `"COLOR"`, `"GRAY"` or `"BLACK_WHITE"` | +| allowGray | boolean | Optional. Set this to `true` to include gray (`#AAAAAA`) in the color picker for aplite running on firmware 3 and above. This is optional because only a subset of the drawing operations support gray on aplite. Defaults to `false` | ##### Example @@ -316,9 +323,40 @@ A color picker containing the 64 supported colors on Basalt and Chalk. { "type": "color", "appKey": "background", - "defaultValue": "FF0000", + "defaultValue": "ff0000", "label": "Background Color", - "sunlight": true + "sunlight": true, + "layout": [ + [false, "00aaff", false], + ["0055ff", "0000ff", "0000aa"], + [false, "5555ff", false] + ] +} +``` + +##### Example + +```javascript +{ + "type": "color", + "appKey": "background", + "defaultValue": "ffffff", + "label": "Background Color", + "sunlight": false, + "layout": "BLACK_WHITE" +} +``` + +##### Example + +```javascript +{ + "type": "color", + "appKey": "background", + "defaultValue": "aaaaaa", + "label": "Background Color", + "sunlight": false, + "allowGray": true } ``` diff --git a/src/scripts/components/color.js b/src/scripts/components/color.js index cebb6f0..fcc1228 100644 --- a/src/scripts/components/color.js +++ b/src/scripts/components/color.js @@ -9,117 +9,225 @@ module.exports = { label: '', description: '' }, - initialize: function(minified) { + initialize: function(minified, clay) { var HTML = minified.HTML; var self = this; - var useSunlight = self.config.sunlight !== false; - var sunlightColorMap = { - '000000': '000000', - '000055': '001e41', - '0000aa': '004387', - '0000ff': '0068ca', - '005500': '2b4a2c', - '005555': '27514f', - '0055aa': '16638d', - '0055ff': '007dce', - '00aa00': '5e9860', - '00aa55': '5c9b72', - '00aaaa': '57a5a2', - '00aaff': '4cb4db', - '00ff00': '8ee391', - '00ff55': '8ee69e', - '00ffaa': '8aebc0', - '00ffff': '84f5f1', - '550000': '4a161b', - '550055': '482748', - '5500aa': '40488a', - '5500ff': '2f6bcc', - '555500': '564e36', - '555555': '545454', - '5555aa': '4f6790', - '5555ff': '4180d0', - '55aa00': '759a64', - '55aa55': '759d76', - '55aaaa': '71a6a4', - '55aaff': '69b5dd', - '55ff00': '9ee594', - '55ff55': '9de7a0', - '55ffaa': '9becc2', - '55ffff': '95f6f2', - 'aa0000': '99353f', - 'aa0055': '983e5a', - 'aa00aa': '955694', - 'aa00ff': '8f74d2', - 'aa5500': '9d5b4d', - 'aa5555': '9d6064', - 'aa55aa': '9a7099', - 'aa55ff': '9587d5', - 'aaaa00': 'afa072', - 'aaaa55': 'aea382', - 'aaaaaa': 'ababab', - 'ffffff': 'ffffff', - 'aaaaff': 'a7bae2', - 'aaff00': 'c9e89d', - 'aaff55': 'c9eaa7', - 'aaffaa': 'c7f0c8', - 'aaffff': 'c3f9f7', - 'ff0000': 'e35462', - 'ff0055': 'e25874', - 'ff00aa': 'e16aa3', - 'ff00ff': 'de83dc', - 'ff5500': 'e66e6b', - 'ff5555': 'e6727c', - 'ff55aa': 'e37fa7', - 'ff55ff': 'e194df', - 'ffaa00': 'f1aa86', - 'ffaa55': 'f1ad93', - 'ffaaaa': 'efb5b8', - 'ffaaff': 'ecc3eb', - 'ffff00': 'ffeeab', - 'ffff55': 'fff1b5', - 'ffffaa': 'fff6d3' - }; /** * @param {string|boolean|number} color * @returns {string} */ function cssColor(color) { - if (color === false) { return 'transparent'; } if (typeof color === 'number') { color = color.toString(16); + } else if (!color) { + return 'transparent'; } - while (color.length < 6) { - color = '0' + color; - } + + color = padColorString(color); return '#' + (useSunlight ? sunlightColorMap[color] : color); } + /** + * @param {string} color + * @return {string} + */ + function padColorString(color) { + color = color.toLowerCase(); + + while (color.length < 6) { + color = '0' + color; + } + + return color; + } + + /** + * @param {number|string} value + * @returns {string|*} + */ + function normalizeColor(value) { + switch (typeof value) { + case 'number': return padColorString(value.toString(16)); + case 'string': return value.replace(/^#|^0x/, ''); + default: return value; + } + } + + /** + * @param {Array.} layout + * @returns {Array} + */ + function flattenLayout(layout) { + return layout.reduce(function(a, b) { + return a.concat(b); + }, []); + } + + /** + * Convert HEX color to LAB. + * Adapted from: https://github.com/antimatter15/rgb-lab + * @param {string} hex + * @returns {Array} - [l, a, b] + */ + function hex2lab(hex) { + hex = hex.replace(/^#|^0x/, ''); + + var r = parseInt(hex.slice(0, 2), 16) / 255; + var g = parseInt(hex.slice(2, 4), 16) / 255; + var b = parseInt(hex.slice(4), 16) / 255; + + r = (r > 0.04045) ? Math.pow((r + 0.055) / 1.055, 2.4) : r / 12.92; + g = (g > 0.04045) ? Math.pow((g + 0.055) / 1.055, 2.4) : g / 12.92; + b = (b > 0.04045) ? Math.pow((b + 0.055) / 1.055, 2.4) : b / 12.92; + + var x = (r * 0.4124 + g * 0.3576 + b * 0.1805) / 0.95047; + var y = (r * 0.2126 + g * 0.7152 + b * 0.0722) / 1.00000; + var z = (r * 0.0193 + g * 0.1192 + b * 0.9505) / 1.08883; + + x = (x > 0.008856) ? Math.pow(x, 1 / 3) : (7.787 * x) + 16 / 116; + y = (y > 0.008856) ? Math.pow(y, 1 / 3) : (7.787 * y) + 16 / 116; + z = (z > 0.008856) ? Math.pow(z, 1 / 3) : (7.787 * z) + 16 / 116; + + return [(116 * y) - 16, 500 * (x - y), 200 * (y - z)]; + } + + /** + * Find the perceptual color distance between two LAB colors + * @param {Array} labA + * @param {Array} labB + * @returns {number} + */ + function deltaE(labA, labB) { + var deltaL = labA[0] - labB[0]; + var deltaA = labA[1] - labB[1]; + var deltaB = labA[2] - labB[2]; + + return Math.sqrt(Math.pow(deltaL, 2) + + Math.pow(deltaA, 2) + + Math.pow(deltaB, 2)); + } + + /** + * Returns the layout based on the connected watch + * @returns {Array} + */ + function autoLayout() { + if (!clay.meta.activeWatchInfo || + clay.meta.activeWatchInfo.firmware.major === 2 || + clay.meta.activeWatchInfo.platform === 'aplite' && + !self.config.allowGray) { + return standardLayouts.BLACK_WHITE; + } + + if (clay.meta.activeWatchInfo.platform === 'aplite' && self.config.allowGray) { + return standardLayouts.GRAY; + } + + return standardLayouts.COLOR; + } + + /** + * @param {number|string} color + * @return {number} + */ + self.roundColorToLayout = function(color) { + var itemValue = normalizeColor(color); + + // if the color is not in the layout we will need find the closest match + if (colorList.indexOf(itemValue) === -1) { + var itemValueLAB = hex2lab(itemValue); + var differenceArr = colorList.map(function(color) { + var colorLAB = hex2lab(normalizeColor(color)); + return deltaE(itemValueLAB, colorLAB); + }); + + // Get the lowest number from the differenceArray + var lowest = Math.min.apply(Math, differenceArr); + + // Get the index for that lowest number + var index = differenceArr.indexOf(lowest); + itemValue = colorList[index]; + } + + return parseInt(itemValue, 16); + }; + + var useSunlight = self.config.sunlight !== false; + var sunlightColorMap = { + '000000': '000000', '000055': '001e41', '0000aa': '004387', '0000ff': '0068ca', + '005500': '2b4a2c', '005555': '27514f', '0055aa': '16638d', '0055ff': '007dce', + '00aa00': '5e9860', '00aa55': '5c9b72', '00aaaa': '57a5a2', '00aaff': '4cb4db', + '00ff00': '8ee391', '00ff55': '8ee69e', '00ffaa': '8aebc0', '00ffff': '84f5f1', + '550000': '4a161b', '550055': '482748', '5500aa': '40488a', '5500ff': '2f6bcc', + '555500': '564e36', '555555': '545454', '5555aa': '4f6790', '5555ff': '4180d0', + '55aa00': '759a64', '55aa55': '759d76', '55aaaa': '71a6a4', '55aaff': '69b5dd', + '55ff00': '9ee594', '55ff55': '9de7a0', '55ffaa': '9becc2', '55ffff': '95f6f2', + 'aa0000': '99353f', 'aa0055': '983e5a', 'aa00aa': '955694', 'aa00ff': '8f74d2', + 'aa5500': '9d5b4d', 'aa5555': '9d6064', 'aa55aa': '9a7099', 'aa55ff': '9587d5', + 'aaaa00': 'afa072', 'aaaa55': 'aea382', 'aaaaaa': 'ababab', 'ffffff': 'ffffff', + 'aaaaff': 'a7bae2', 'aaff00': 'c9e89d', 'aaff55': 'c9eaa7', 'aaffaa': 'c7f0c8', + 'aaffff': 'c3f9f7', 'ff0000': 'e35462', 'ff0055': 'e25874', 'ff00aa': 'e16aa3', + 'ff00ff': 'de83dc', 'ff5500': 'e66e6b', 'ff5555': 'e6727c', 'ff55aa': 'e37fa7', + 'ff55ff': 'e194df', 'ffaa00': 'f1aa86', 'ffaa55': 'f1ad93', 'ffaaaa': 'efb5b8', + 'ffaaff': 'ecc3eb', 'ffff00': 'ffeeab', 'ffff55': 'fff1b5', 'ffffaa': 'fff6d3' + }; + /* eslint-disable comma-spacing, no-multi-spaces, max-len, - standard/array-bracket-even-spacing */ - var layout = self.config.layout || [ - [false , false , '55ff00', 'aaff55', false , 'ffff55', 'ffffaa', false , false ], - [false , 'aaffaa', '55ff55', '00ff00', 'aaff00', 'ffff00', 'ffaa55', 'ffaaaa', false ], - ['55ffaa', '00ff55', '00aa00', '55aa00', 'aaaa55', 'aaaa00', 'ffaa00', 'ff5500', 'ff5555'], - ['aaffff', '00ffaa', '00aa55', '55aa55', '005500', '555500', 'aa5500', 'ff0000', 'ff0055'], - [false , '55aaaa', '00aaaa', '005555', 'ffffff', '000000', 'aa5555', 'aa0000', false ], - ['55ffff', '00ffff', '00aaff', '0055aa', 'aaaaaa', '555555', '550000', 'aa0055', 'ff55aa'], - ['55aaff', '0055ff', '0000ff', '0000aa', '000055', '550055', 'aa00aa', 'ff00aa', 'ffaaff'], - [false , '5555aa', '5555ff', '5500ff', '5500aa', 'aa00ff', 'ff00ff', 'ff55ff', false ], - [false , false , false , 'aaaaff', 'aa55ff', 'aa55aa', false , false , false ] - ]; + standard/array-bracket-even-spacing */ + var standardLayouts = { + COLOR: [ + [false , false , '55ff00', 'aaff55', false , 'ffff55', 'ffffaa', false , false ], + [false , 'aaffaa', '55ff55', '00ff00', 'aaff00', 'ffff00', 'ffaa55', 'ffaaaa', false ], + ['55ffaa', '00ff55', '00aa00', '55aa00', 'aaaa55', 'aaaa00', 'ffaa00', 'ff5500', 'ff5555'], + ['aaffff', '00ffaa', '00aa55', '55aa55', '005500', '555500', 'aa5500', 'ff0000', 'ff0055'], + [false , '55aaaa', '00aaaa', '005555', 'ffffff', '000000', 'aa5555', 'aa0000', false ], + ['55ffff', '00ffff', '00aaff', '0055aa', 'aaaaaa', '555555', '550000', 'aa0055', 'ff55aa'], + ['55aaff', '0055ff', '0000ff', '0000aa', '000055', '550055', 'aa00aa', 'ff00aa', 'ffaaff'], + [false , '5555aa', '5555ff', '5500ff', '5500aa', 'aa00ff', 'ff00ff', 'ff55ff', false ], + [false , false , false , 'aaaaff', 'aa55ff', 'aa55aa', false , false , false ] + ], + GRAY: [ + ['000000', 'aaaaaa', 'ffffff'] + ], + BLACK_WHITE: [ + ['000000', 'ffffff'] + ] + }; /* eslint-enable */ + var layout = self.config.layout || autoLayout(); + + if (typeof layout === 'string') { + layout = standardLayouts[layout]; + } + + // make sure layout is a 2D array + if (!Array.isArray(layout[0])) { + layout = [layout]; + } + + var colorList = flattenLayout(layout).map(function(item) { + return normalizeColor(item); + }).filter(function(item) { + return item; + }); + var grid = ''; - var itemWidth = 100 / layout[0].length; - var itemHeight = 100 / layout.length; + var rows = layout.length; + var cols = 0; + layout.forEach(function(row) { + cols = row.length > cols ? row.length : cols; + }); + var itemWidth = 100 / cols; + var itemHeight = 100 / rows; var $elem = self.$element; - for (var i = 0; i < layout.length; i++) { - for (var j = 0; j < layout[i].length; j++) { + for (var i = 0; i < rows; i++) { + for (var j = 0; j < cols; j++) { - var color = layout[i][j]; + var color = normalizeColor(layout[i][j]); var selectable = (color ? ' selectable' : ''); var roundedTL = (i === 0 && j === 0) || i === 0 && !layout[i][j - 1] || @@ -146,7 +254,7 @@ module.exports = { grid += '} layout + * @returns {Array} + */ +function flattenLayout(layout) { + return layout.reduce(function(a, b) { + return a.concat(b); + }, []); +} + +/** + * @param {Array|string} [layout=color] + * @param {Array} [expectedColors] + * @return {void} + */ +function testCustomLayout(layout, expectedColors) { + + describe('layout: ' + JSON.stringify(layout || 'default'), function() { + + describe('Normal', function() { + testColors(false, layout, expectedColors); + }); + + describe('Sunlight', function() { + testColors(true, layout, expectedColors); + }); + }); +} + +/** + * @param {string} platform + * @param {Array} layout + * @param {boolean} allowGray + * @param {string} desc + * @param {Object} activeWatchInfo + * @return {void} + */ +function testAutoLayout(platform, layout, allowGray, desc, activeWatchInfo) { + it('chooses the best layout for the ' + (desc || platform) + + ' platform when allowGray is ' + allowGray, + function() { + var clayConfig = fixture.clayConfig( + [{type: 'color', allowGray: allowGray}], + true, + true, + {}, + { + activeWatchInfo: activeWatchInfo + } + ); + var colorItem = clayConfig.getItemsByType('color')[0]; + assert.deepEqual(colorItem._layout, layout); + }); +} + +/** + * @param {number|string} input + * @param {number} expected + * @param {array|string} layout + * @return {void} + */ +function testClosestToLayout(input, expected, layout) { + it('rounds ' + input + ' to ' + expected.toString(16) + + ' in layout: ' + JSON.stringify(layout), + function() { + var clayConfig; + var colorItem; + + clayConfig = fixture.clayConfig([{ + type: 'color', + sunlight: false, + layout: layout + }]); + colorItem = clayConfig.getItemsByType('color')[0]; + colorItem.set(input); + assert.strictEqual(colorItem.get(), expected); + + clayConfig = fixture.clayConfig([{ + type: 'color', + sunlight: false, + layout: layout + }]); + colorItem = clayConfig.getItemsByType('color')[0]; + colorItem.set(input); + assert.strictEqual(colorItem.get(), expected); + }); +} + +/** + * @param {boolean} sunlight + * @param {Array|string} [layout=color] + * @param {Array} [expectedColors] + * @return {void} + */ +function testColors(sunlight, layout, expectedColors) { + var clayConfig; + var colorItem; + var $colorBoxes; + var colors; + + beforeEach(function() { + clayConfig = fixture.clayConfig([ + { + type: 'color', + layout: layout, + sunlight: sunlight + } + ]); + colorItem = clayConfig.getItemsByType('color')[0]; + + layout = layout || 'COLOR'; + if (typeof layout === 'string') { + layout = standardLayouts[layout]; + } + + colors = expectedColors || flattenLayout(layout); + $colorBoxes = colorItem.$element.select('.color-box'); + }); + + it('Has the correct items in the layout', function() { + colors.forEach(function(color, index) { + if (color === false) { + assert.strictEqual($colorBoxes[index].dataset.value, undefined); + } else { + assert.strictEqual( + parseInt($colorBoxes[index].dataset.value, 10), + parseInt(color || 0, 16) + ); + } + }); + }); + + it('sets the color correctly', function() { + colors.forEach(function(color, index) { + if (color === false) { + assert.strictEqual( + $colorBoxes[index].style.backgroundColor, + 'transparent' + ); + } else { + var normalizedColor = normalizeColor(color); + assert.strictEqual( + $colorBoxes[index].style.backgroundColor, + hexToRgb(sunlight ? sunlightColorMap[normalizedColor] : normalizedColor) + ); + } + }); + }); +} + describe('component - color', function() { it('shows the sunlit colors in the value display', function() { var clayConfig = fixture.clayConfig([ @@ -105,4 +323,158 @@ describe('component - color', function() { $picker[0].click(); assert.strictEqual($picker.get('classList').contains('show'), false); }); + + describe('color rounding', function() { + var layout = 'GRAY'; + testClosestToLayout('000000', 0x000000, layout); + testClosestToLayout('005500', 0x000000, layout); + testClosestToLayout('55aa55', 0xaaaaaa, layout); + testClosestToLayout('ffaaff', 0xaaaaaa, layout); + testClosestToLayout('ffffaa', 0xffffff, layout); + testClosestToLayout('ffffff', 0xffffff, layout); + + layout = 'BLACK_WHITE'; + testClosestToLayout('000000', 0x000000, layout); + testClosestToLayout('005500', 0x000000, layout); + testClosestToLayout('55aa55', 0xffffff, layout); + testClosestToLayout('ffaaff', 0xffffff, layout); + testClosestToLayout('ffffaa', 0xffffff, layout); + testClosestToLayout('ffffff', 0xffffff, layout); + + layout = 'COLOR'; + testClosestToLayout('000000', 0x000000, layout); + testClosestToLayout('005500', 0x005500, layout); + testClosestToLayout('55bb55', 0x55aa55, layout); + testClosestToLayout('ff99ff', 0xffaaff, layout); + testClosestToLayout('ffffee', 0xffffff, layout); + testClosestToLayout('ffffff', 0xffffff, layout); + + layout = ['ff0000', 'ff5500', 'ff00ff', '00ff00', '555555']; + testClosestToLayout('000000', 0x555555, layout); + testClosestToLayout('ff0000', 0xff0000, layout); + testClosestToLayout('ff1111', 0xff0000, layout); + testClosestToLayout('00aa00', 0x00ff00, layout); + testClosestToLayout('ff55ff', 0xff00ff, layout); + testClosestToLayout('aaaaaa', 0x555555, layout); + testClosestToLayout('ffffff', 0x555555, layout); + }); + + describe('layouts', function() { + + // allow gray does nothing for 2.x + testAutoLayout('aplite', standardLayouts.BLACK_WHITE, true, 'aplite (2.x)', + null + ); + testAutoLayout('aplite', standardLayouts.BLACK_WHITE, true, 'aplite (2.x)', { + platform: 'aplite', + model: 'qemu_platform_aplite', + language: 'en_US', + firmware: { + major: 2, + minor: 10, + patch: 0, + suffix: '' + } + }); + testAutoLayout('aplite', standardLayouts.BLACK_WHITE, false, 'aplite (2.x)', + null + ); + testAutoLayout('aplite', standardLayouts.BLACK_WHITE, false, 'aplite (2.x)', { + platform: 'aplite', + model: 'qemu_platform_aplite', + language: 'en_US', + firmware: { + major: 2, + minor: 10, + patch: 0, + suffix: '' + } + }); + testAutoLayout('aplite', standardLayouts.BLACK_WHITE, false, 'aplite (3.x)', { + platform: 'aplite', + model: 'qemu_platform_aplite', + language: 'en_US', + firmware: { + major: 3, + minor: 10, + patch: 0, + suffix: '' + } + }); + testAutoLayout('aplite', standardLayouts.GRAY, true, 'aplite (3.x)', { + platform: 'aplite', + model: 'qemu_platform_aplite', + language: 'en_US', + firmware: { + major: 3, + minor: 10, + patch: 0, + suffix: '' + } + }); + testAutoLayout('basalt', standardLayouts.COLOR, true, '', { + platform: 'basalt', + model: 'qemu_platform_basalt', + language: 'en_US', + firmware: { + major: 3, + minor: 10, + patch: 0, + suffix: '' + } + }); + testAutoLayout('chalk', standardLayouts.COLOR, true, '', { + platform: 'chalk', + model: 'qemu_platform_chalk', + language: 'en_US', + firmware: { + major: 3, + minor: 10, + patch: 0, + suffix: '' + } + }); + + testCustomLayout(); + testCustomLayout('COLOR'); + testCustomLayout('GRAY'); + testCustomLayout('BLACK_WHITE'); + testCustomLayout(['aaffaa', '55ff55', '00ff00']); + testCustomLayout([false, '55ff55', '00ff00']); + testCustomLayout([['aaffaa', '55ff55', '00ff00']]); + testCustomLayout( + [['AAFFAA', '#55ff55', '0x00ff00', 0xff5500, null]], + ['aaffaa', '55ff55', '00ff00', 'ff5500', false] + ); + testCustomLayout([ + ['aaffaa', '55ff55', '00ff00'], + ['005555', 'ffffff', '000000']] + ); + testCustomLayout([ + ['aaffaa', '55ff55', '00ff00'], + [false, 'ffffff', false]] + ); + testCustomLayout( + [ + ['aaffaa', '55ff55', '00ff00'], + [false, 'ffffff'] + ], + ['aaffaa', '55ff55', '00ff00', false, 'ffffff', false] + ); + testCustomLayout( + [ + ['aaffaa', '55ff55', false], + [false, 'ffffff'] + ], + ['aaffaa', '55ff55', false, false, 'ffffff', false] + ); + testCustomLayout( + [ + ['aaffaa', '55ff55'], + [false, 'ffffff', '000000'] + ], + ['aaffaa', '55ff55', false, false, 'ffffff', '000000'] + ); + + }); }); diff --git a/test/spec/index.js b/test/spec/index.js index 734e690..38cf8a0 100644 --- a/test/spec/index.js +++ b/test/spec/index.js @@ -62,8 +62,6 @@ describe('Clay', function() { it('handles the "showConfiguration" event if autoHandleEvents is not false', function() { - this.timeout(10000); // 10 seconds - stubPebble(); var clay = fixture.clay([]);