diff --git a/package.json b/package.json
index 70597f2d8..2a88a95f5 100644
--- a/package.json
+++ b/package.json
@@ -9,7 +9,7 @@
"jest": "jest",
"lerna": "lerna bootstrap -- --no-optional --no-package-lock",
"lint": "eslint packages/clay-*/src/*.js packages/clay-*/src/**/*.js && npm run mcritic",
- "mcritic": "mcritic packages/ --ignore '**/{browserslist-config-clay-components,generator-metal-clay,clay-dropdown,clay-alert,clay-list,clay-management-toolbar,clay-card,node_modules}/**'",
+ "mcritic": "mcritic packages/ --ignore '**/{browserslist-config-clay-components,generator-metal-clay,clay-dropdown,clay-alert,clay-list,clay-management-toolbar,clay-card,clay-table,node_modules}/**'",
"precommit": "lint-staged",
"prettier": "prettier-eslint packages/clay-*/src/*.js packages/clay-*/src/**/*.js",
"start": "http-server . -p 4000",
diff --git a/packages/clay-table/LICENSE.md b/packages/clay-table/LICENSE.md
new file mode 100644
index 000000000..70f93e946
--- /dev/null
+++ b/packages/clay-table/LICENSE.md
@@ -0,0 +1,29 @@
+# Software License Agreement (BSD License)
+
+Copyright (c) 2014, Liferay Inc.
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms, with or without modification, are
+permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above
+ copyright notice, this list of conditions and the
+ following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the
+ following disclaimer in the documentation and/or other
+ materials provided with the distribution.
+
+* The name of Liferay Inc. may not be used to endorse or promote products
+ derived from this software without specific prior
+ written permission of Liferay Inc.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/packages/clay-table/README.md b/packages/clay-table/README.md
new file mode 100644
index 000000000..5138b1083
--- /dev/null
+++ b/packages/clay-table/README.md
@@ -0,0 +1,26 @@
+# clay-table
+
+Metal Clay Table component
+
+## Setup
+
+1. Install NodeJS >= v0.12.0 and NPM >= v3.0.0, if you don't have it yet. You
+can find it [here](https://nodejs.org).
+
+2. Install local dependencies:
+
+ ```
+ npm install
+ ```
+
+3. Build the code:
+
+ ```
+ npm run build
+ ```
+
+4. Open the demo at demos/index.html on your browser.
+
+## Contribute
+
+We'd love to get contributions from you! Please, check our [Contributing Guidelines](CONTRIBUTING.md) to see how you can help us improve.
diff --git a/packages/clay-table/demos/image.jpg b/packages/clay-table/demos/image.jpg
new file mode 100644
index 000000000..fbaaa2468
Binary files /dev/null and b/packages/clay-table/demos/image.jpg differ
diff --git a/packages/clay-table/demos/index.html b/packages/clay-table/demos/index.html
new file mode 100644
index 000000000..5fcbf15c7
--- /dev/null
+++ b/packages/clay-table/demos/index.html
@@ -0,0 +1,812 @@
+
+
+
+
+
+ Demo: ClayTable
+
+
+
+
+
+
+
+
+
+ ClayTable
+
+
+
+
+
+
+
Simple Table with links
+
+
+
+
+
+
+
Simple Table with Label
+
+
+
+
+
+
+
Simple Table with Progress Bar
+
+
+
+
+
+
+
+
+
Selectable Table with Sticker
+
+
+
+
+
+
+
Selectable Table with Action Menu
+
+
+
+
+
+
+
Selectable Table with Quick Action Menu
+
+
+
+
+
+
+
Selectable Table with group separator
+
+
+
+
+
+
+
Selectable Table with Selected Items
+
+
+
+
+
+
+
diff --git a/packages/clay-table/package.json b/packages/clay-table/package.json
new file mode 100644
index 000000000..1868c66aa
--- /dev/null
+++ b/packages/clay-table/package.json
@@ -0,0 +1,61 @@
+{
+ "name": "clay-table",
+ "version": "1.0.0-alpha.8",
+ "description": "Metal ClayTable component",
+ "license": "BSD",
+ "repository": "https://github.com/metal/metal-clay-components/tree/master/packages/clay-table",
+ "engines": {
+ "node": ">=0.12.0",
+ "npm": ">=3.0.0"
+ },
+ "main": "lib/ClayTable.js",
+ "esnext:main": "src/ClayTable.js",
+ "jsnext:main": "src/ClayTable.js",
+ "files": [
+ "lib",
+ "src",
+ "test"
+ ],
+ "scripts": {
+ "build": "npm run soy && webpack",
+ "compile": "babel -d lib/ src/ -s --ignore src/__tests__",
+ "prepublish": "npm run soy && npm run compile",
+ "soy": "metalsoy --soyDeps '../../node_modules/clay-+(dropdown|label|sticker|progress-bar|button|checkbox|icon|link|radio)/src/**/*.soy'"
+ },
+ "keywords": [
+ "clay",
+ "metal"
+ ],
+ "dependencies": {
+ "clay-button": "^1.0.0-alpha.8",
+ "clay-checkbox": "^1.0.0-alpha.5",
+ "clay-dropdown": "^1.0.0-alpha.8",
+ "clay-icon": "^1.0.0-alpha.5",
+ "clay-label": "^1.0.0-alpha.8",
+ "clay-link": "^1.0.0-alpha.8",
+ "clay-progress-bar": "^1.0.0-alpha.5",
+ "clay-sticker": "^1.0.0-alpha.5",
+ "metal-component": "^2.14.0",
+ "metal-dom": "^2.14.0",
+ "metal-events": "^2.14.0",
+ "metal-soy": "^2.14.0",
+ "metal-state": "^2.14.0",
+ "metal-web-component": "^2.14.0",
+ "metal": "^2.14.0"
+ },
+ "devDependencies": {
+ "babel-cli": "^6.24.1",
+ "babel-core": "^6.25.0",
+ "babel-loader": "^7.0.0",
+ "babel-plugin-transform-node-env-inline": "^0.1.1",
+ "babel-preset-env": "^1.6.0",
+ "browserslist-config-clay-components": "^1.0.0-alpha.2",
+ "clay": "^2.0.0-beta.4",
+ "metal-dom": "^2.13.2",
+ "metal-tools-soy": "^4.2.1",
+ "webpack": "^3.0.0"
+ },
+ "browserslist": [
+ "extends browserslist-config-clay-components"
+ ]
+}
diff --git a/packages/clay-table/src/ClayTable.js b/packages/clay-table/src/ClayTable.js
new file mode 100644
index 000000000..7a9185789
--- /dev/null
+++ b/packages/clay-table/src/ClayTable.js
@@ -0,0 +1,161 @@
+import './ClayTableItem';
+import 'clay-link';
+import {Config} from 'metal-state';
+import {EventHandler} from 'metal-events';
+import Component from 'metal-component';
+import defineWebComponent from 'metal-web-component';
+import dom from 'metal-dom';
+import itemsValidator from './items_validator';
+import Soy from 'metal-soy';
+
+import templates from './ClayTable.soy.js';
+
+/**
+ * Metal ClayTable component.
+ */
+class ClayTable extends Component {
+ /**
+ * @inheritDoc
+ */
+ attached() {
+ this.eventHandler_.add(
+ dom.delegate(
+ document,
+ 'click',
+ 'body',
+ this.handleClickDocument_.bind(this)
+ ),
+ dom.delegate(this.element, 'focus', 'tr', this.handleFocus_)
+ );
+ }
+
+ /**
+ * @inheritDoc
+ */
+ created() {
+ this.eventHandler_ = new EventHandler();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ detached() {
+ super.detached();
+ this.eventHandler_.removeAllListeners();
+ }
+
+ /**
+ * Propagate the change of the checkbox event.
+ * @param {!Event} event
+ * @private
+ */
+ handleClickCheckbox_(event) {
+ this.emit('itemToggled', event);
+ }
+
+ /**
+ * Handle click in document for remove the class `table-focus` of tr.
+ * @private
+ */
+ handleClickDocument_() {
+ dom.removeClasses(this.element.querySelectorAll('tr'), 'table-focus');
+ }
+
+ /**
+ * Handle focus the tr for add class `table-focus`.
+ * @param {!Event} event
+ * @private
+ */
+ handleFocus_(event) {
+ const getFirstTable = dom.closest(event.target, 'table');
+ const getFirstTr = dom.closest(event.target, 'tr');
+
+ dom.removeClasses(getFirstTable.querySelectorAll('tr'), 'table-focus');
+ dom.addClasses(getFirstTr, 'table-focus');
+ }
+
+ /**
+ * Handle button sort in header.
+ * @param {!Event} event
+ * @private
+ */
+ handleSortColumn_(event) {
+ this.emit('sortColumn', event);
+ }
+}
+
+/**
+ * State definition.
+ * @static
+ * @type {!Object}
+ */
+ClayTable.STATE = {
+ /**
+ * CSS classes to be applied to the element.
+ * @instance
+ * @memberof ClayTable
+ * @type {?string|undefined}
+ * @default undefined
+ */
+ elementClasses: Config.string(),
+
+ /**
+ * Used to render the header of a column.
+ * @instance
+ * @memberof ClayTable
+ * @type {?array|undefined}
+ * @default undefined
+ */
+ header: Config.arrayOf(
+ Config.shapeOf({
+ colSpan: Config.number(),
+ elementClasses: Config.string(),
+ label: Config.string(),
+ sort: Config.bool().value(false),
+ sortDirection_: Config.oneOf(['down', 'up']).value('down'),
+ })
+ ),
+
+ /**
+ * Id to be applied to the element.
+ * @instance
+ * @memberof ClayTable
+ * @type {?string|undefined}
+ * @default undefined
+ */
+ id: Config.string(),
+
+ /**
+ * List the items of the table.
+ * @instance
+ * @memberof ClayTable
+ * @type {?array|undefined}
+ * @default undefined
+ */
+ items: itemsValidator,
+
+ /**
+ * Table responsive sizes. Available `lg`, `md`, `sm` and `xl`.
+ * @instance
+ * @memberof ClayTable
+ * @type {?string|undefined}
+ * @default undefined
+ */
+ size: Config.oneOf(['lg', 'md', 'sm', 'xl']),
+
+ /**
+ * The path to the SVG spritemap file containing the icons.
+ * @instance
+ * @memberof ClayTable
+ * @type {!string}
+ * @default undefined
+ */
+ spritemap: Config.string().required(),
+};
+
+defineWebComponent('clay-table', ClayTable);
+
+Soy.register(ClayTable, templates);
+
+export {ClayTable};
+export default ClayTable;
diff --git a/packages/clay-table/src/ClayTable.soy b/packages/clay-table/src/ClayTable.soy
new file mode 100644
index 000000000..d3defa41a
--- /dev/null
+++ b/packages/clay-table/src/ClayTable.soy
@@ -0,0 +1,205 @@
+{namespace ClayTable}
+
+/**
+ * This renders the component's whole content.
+ */
+{template .render}
+ {@param spritemap: string}
+ {@param? elementClasses: string}
+ {@param? handleClickCheckbox_: any}
+ {@param? handleSortColumn_: any}
+ {@param? header: list<[
+ colSpan: int,
+ elementClasses: string,
+ label: string,
+ sort: bool,
+ sortDirection_: string
+ ]>}
+ {@param? id: string}
+ {@param? items: list<[
+ actionColumnElementClasses: string,
+ actionItems: list<[
+ disabled: bool,
+ href: string,
+ icon: string,
+ label: string,
+ quickAction: bool,
+ separator: bool
+ ]>,
+ columns: list<[
+ buttonStyle: string,
+ elementClasses: string,
+ href: string,
+ label: string,
+ labelStyle: string,
+ progressBar: [
+ maxValue: int,
+ minValue: int,
+ status: string,
+ value: int
+ ],
+ type: string,
+ useEllipse: bool
+ ]>,
+ disabled: bool,
+ group: string,
+ inputName: string,
+ inputValue: string,
+ items: list>,
+ selectable: bool,
+ selectableElementClasses: string,
+ selected: bool,
+ stickerElementClasses: string,
+ stickerImageAlt: string,
+ stickerImageSrc: string,
+ stickerLabel: string,
+ stickerStyle: string,
+ stickerShape: string
+ ]>}
+ {@param? size: string}
+
+ {let $attributes kind="attributes"}
+ class="table table-autofit table-hover table-list show-quick-actions-on-hover
+ {if $elementClasses}
+ {sp}{$elementClasses}
+ {/if}
+ "
+
+ {if $id}
+ id="{$id}"
+ {/if}
+ {/let}
+
+ {let $classes kind="text"}
+ table-responsive
+ {if $size}
+ -{$size}
+ {/if}
+ {/let}
+
+
+
+ {if $header}
+
+
+ {call .header}
+ {param handleSortColumn_: $handleSortColumn_ /}
+ {param header: $header /}
+ {param spritemap: $spritemap /}
+ {/call}
+
+
+ {/if}
+ {if $items}
+
+ {call .body}
+ {param handleClickCheckbox_: $handleClickCheckbox_ /}
+ {param items: $items /}
+ {param spritemap: $spritemap /}
+ {/call}
+
+ {/if}
+
+
+{/template}
+
+/**
+ * This renders a rows of the table.
+ */
+{template .body}
+ {@param items: list>}
+ {@param spritemap: string}
+ {@param? handleClickCheckbox_: any}
+
+ {foreach $item in $items}
+ {if $item.group}
+
+ {$item.group}
+
+ {if $item.items}
+ {foreach $itemToGroup in $item.items}
+ {call ClayTableItem.render}
+ {param actionColumnElementClasses: $itemToGroup.actionColumnElementClasses /}
+ {param actionItems: $itemToGroup.actionItems /}
+ {param columns: $itemToGroup.columns /}
+ {param disabled: $itemToGroup.disabled /}
+ {param events: ['itemToggled': $handleClickCheckbox_] /}
+ {param inputName: $itemToGroup.inputName /}
+ {param inputValue: $itemToGroup.inputValue /}
+ {param selectable: $itemToGroup.selectable /}
+ {param selectableElementClasses: $itemToGroup.selectableElementClasses /}
+ {param selected: $itemToGroup.selected /}
+ {param spritemap: $spritemap /}
+ {param stickerElementClasses: $itemToGroup.stickerElementClasses /}
+ {param stickerImageAlt: $itemToGroup.stickerImageAlt /}
+ {param stickerImageSrc: $itemToGroup.stickerImageSrc /}
+ {param stickerLabel: $itemToGroup.stickerLabel /}
+ {param stickerShape: $itemToGroup.stickerShape /}
+ {param stickerStyle: $itemToGroup.stickerStyle /}
+ {/call}
+ {/foreach}
+ {/if}
+ {else}
+ {call ClayTableItem.render}
+ {param actionColumnElementClasses: $item.actionColumnElementClasses /}
+ {param actionItems: $item.actionItems /}
+ {param columns: $item.columns /}
+ {param disabled: $item.disabled /}
+ {param events: ['itemToggled': $handleClickCheckbox_] /}
+ {param inputName: $item.inputName /}
+ {param inputValue: $item.inputValue /}
+ {param selectable: $item.selectable /}
+ {param selectableElementClasses: $item.selectableElementClasses /}
+ {param selected: $item.selected /}
+ {param spritemap: $spritemap /}
+ {param stickerElementClasses: $item.stickerElementClasses /}
+ {param stickerImageAlt: $item.stickerImageAlt /}
+ {param stickerImageSrc: $item.stickerImageSrc /}
+ {param stickerLabel: $item.stickerLabel /}
+ {param stickerShape: $item.stickerShape /}
+ {param stickerStyle: $item.stickerStyle /}
+ {/call}
+ {/if}
+ {/foreach}
+{/template}
+
+/**
+ * This renders columns to the header of the table.
+ */
+{template .header}
+ {@param header: list>}
+ {@param spritemap: string}
+ {@param? handleSortColumn_: any}
+
+ {foreach $item in $header}
+ {let $thAttributes kind="attributes"}
+ class="
+ {if $item.elementClasses}
+ {$item.elementClasses}
+ {/if}
+ "
+
+ {if $item.colSpan}
+ colspan="{$item.colSpan}"
+ {/if}
+ {/let}
+
+
+ {if $item.label and not $item.sort}
+ {$item.label}
+ {elseif $item.sort and $item.label}
+ {let $icon: $item.sortDirection_ ?: 'down' /}
+
+ {call ClayLink.render}
+ {param events: ['click': $handleSortColumn_] /}
+ {param href: '#sort' /}
+ {param icon: 'order-arrow-' + $icon /}
+ {param iconAlignment: 'right' /}
+ {param id: '' + index($item) /}
+ {param label: $item.label /}
+ {param spritemap: $spritemap /}
+ {/call}
+ {/if}
+
+ {/foreach}
+{/template}
diff --git a/packages/clay-table/src/ClayTableItem.js b/packages/clay-table/src/ClayTableItem.js
new file mode 100644
index 000000000..511461cfa
--- /dev/null
+++ b/packages/clay-table/src/ClayTableItem.js
@@ -0,0 +1,209 @@
+import 'clay-button';
+import 'clay-checkbox';
+import 'clay-dropdown';
+import 'clay-icon';
+import 'clay-label';
+import 'clay-link';
+import 'clay-progress-bar';
+import 'clay-sticker';
+import {actionsItemsValidator, columnsValidator} from './items_validator';
+import {Config} from 'metal-state';
+import Component from 'metal-component';
+import defineWebComponent from 'metal-web-component';
+import dom from 'metal-dom';
+import Soy from 'metal-soy';
+
+import templates from './ClayTableItem.soy.js';
+
+/**
+ * Metal ClayTableItem component.
+ */
+class ClayTableItem extends Component {
+ /**
+ * Handle input of type `checkbox` for add class `table-active` in tr.
+ * @param {!Event} event
+ * @private
+ */
+ handleItemToggled_(event) {
+ dom.toggleClasses(this.element, 'table-active');
+
+ this.emit('itemToggled', event);
+ }
+}
+
+/**
+ * State definition.
+ * @static
+ * @type {!Object}
+ */
+ClayTableItem.STATE = {
+ /**
+ * CSS classes to be applied to the td of the actions menu.
+ * @instance
+ * @memberof ClayTableItem
+ * @type {?string|undefined}
+ * @default undefined
+ */
+ actionColumnElementClasses: Config.string(),
+
+ /**
+ * List of items to display in the actions menu.
+ * @instance
+ * @memberof ClayTableItem
+ * @type {?array|undefined}
+ * @default undefined
+ */
+ actionItems: actionsItemsValidator,
+
+ /**
+ * List of the columns in the row.
+ * @instance
+ * @memberof ClayTableItem
+ * @type {?array|undefined}
+ * @default undefined
+ */
+ columns: columnsValidator,
+
+ /**
+ * Name of the content renderer to use template variants.
+ * @instance
+ * @memberof ClayTableItem
+ * @type {?string|undefined}
+ * @default undefined
+ */
+ contentRenderer: Config.string(),
+
+ /**
+ * Flag to indicate if the item is disabled or not.
+ * @instance
+ * @memberof ClayTableItem
+ * @type {?bool}
+ * @default false
+ */
+ disabled: Config.bool().value(false),
+
+ /**
+ * Name to be applied to the input element.
+ * @instance
+ * @memberof ClayTableItem
+ * @type {?string|undefined}
+ * @default undefined
+ */
+ inputName: Config.string(),
+
+ /**
+ * Value to be applied to the input element.
+ * @instance
+ * @memberof ClayTableItem
+ * @type {?string|undefined}
+ * @default undefined
+ */
+ inputValue: Config.string(),
+
+ /**
+ * Flag to indicate if the item is selectable.
+ * @instance
+ * @memberof ClayTableItem
+ * @type {?bool}
+ * @default false
+ */
+ selectable: Config.bool().value(false),
+
+ /**
+ * CSS classes to be applied to the td of the selectable.
+ * @instance
+ * @memberof ClayTableItem
+ * @type {?string|undefined}
+ * @default undefined
+ */
+ selectableElementClasses: Config.string(),
+
+ /**
+ * Flag to indicate if the item is selected or not.
+ * @instance
+ * @memberof ClayTableItem
+ * @type {?bool}
+ * @default false
+ */
+ selected: Config.bool().value(false),
+
+ /**
+ * The path to the SVG spritemap file containing the icons.
+ * @instance
+ * @memberof ClayTableItem
+ * @type {!string}
+ * @default undefined
+ */
+ spritemap: Config.string().required(),
+
+ /**
+ * CSS classes to be applied to the td of the sticker.
+ * @instance
+ * @memberof ClayTableItem
+ * @type {?string|undefined}
+ * @default undefined
+ */
+ stickerElementClasses: Config.string(),
+
+ /**
+ * Alternate text of the image sticker.
+ * @instance
+ * @memberof ClayTableItem
+ * @type {?string|undefined}
+ * @default undefined
+ */
+ stickerImageAlt: Config.string(),
+
+ /**
+ * Source of the image to be rendered inside the sticker.
+ * @instance
+ * @memberof ClayTableItem
+ * @type {?string|undefined}
+ * @default undefined
+ */
+ stickerImageSrc: Config.string(),
+
+ /**
+ * Sets the text to be rendered inside sticker.
+ * @instance
+ * @memberof ClayTableItem
+ * @type {?string|undefined}
+ * @default undefined
+ */
+ stickerLabel: Config.string(),
+
+ /**
+ * Shape of sticker. Available shapes are `circle`, `rounded`.
+ * @instance
+ * @memberof ClayTableItem
+ * @type {?string}
+ * @default circle
+ */
+ stickerShape: Config.string().value('circle'),
+
+ /**
+ * Sticker style. Available sizes are: `danger`, `dark`, `info`, `light`,
+ * `primary`, `secondary`, `success`, `warning`.
+ * @instance
+ * @memberof ClayTableItem
+ * @type {?string}
+ * @default primary
+ */
+ stickerStyle: Config.oneOf([
+ 'danger',
+ 'dark',
+ 'info',
+ 'light',
+ 'primary',
+ 'secondary',
+ 'success',
+ 'warning',
+ ]).value('primary'),
+};
+
+defineWebComponent('clay-table-item', ClayTableItem);
+
+Soy.register(ClayTableItem, templates);
+
+export {ClayTableItem};
+export default ClayTableItem;
diff --git a/packages/clay-table/src/ClayTableItem.soy b/packages/clay-table/src/ClayTableItem.soy
new file mode 100644
index 000000000..e636c8313
--- /dev/null
+++ b/packages/clay-table/src/ClayTableItem.soy
@@ -0,0 +1,271 @@
+{namespace ClayTableItem}
+
+/**
+ * This renders the component's whole content.
+ */
+{template .render}
+ {@param spritemap: string}
+ {@param? actionColumnElementClasses: string}
+ {@param? actionItems: list<[
+ disabled: bool,
+ href: string,
+ icon: string,
+ label: string,
+ quickAction: bool,
+ separator: bool
+ ]>}
+ {@param? columns: list<[
+ buttonStyle: string,
+ elementClasses: string,
+ href: string,
+ label: string,
+ labelStyle: string,
+ progressBar: [
+ maxValue: int,
+ minValue: int,
+ status: string,
+ value: int
+ ],
+ type: string,
+ useEllipse: bool
+ ]>}
+ {@param? contentRenderer: string}
+ {@param? disabled: bool}
+ {@param? handleItemToggled_: any}
+ {@param? inputName: string}
+ {@param? inputValue: string}
+ {@param? selectable: bool}
+ {@param? selectableElementClasses: string}
+ {@param? selected: bool}
+ {@param? stickerElementClasses: string}
+ {@param? stickerImageAlt: string}
+ {@param? stickerImageSrc: string}
+ {@param? stickerLabel: string}
+ {@param? stickerShape: string}
+ {@param? stickerStyle: string}
+
+ {let $attributes kind="attributes"}
+ class="
+ {if $selectable and $selected}
+ table-active
+ {/if}
+ "
+ {/let}
+
+
+ {call .content}
+ {param actionColumnElementClasses: $actionColumnElementClasses /}
+ {param actionItems: $actionItems /}
+ {param columns: $columns /}
+ {param contentRenderer: $contentRenderer /}
+ {param disabled: $disabled /}
+ {param handleItemToggled_: $handleItemToggled_ /}
+ {param inputName: $inputName /}
+ {param inputValue: $inputValue /}
+ {param selectable: $selectable /}
+ {param selectableElementClasses: $selectableElementClasses /}
+ {param selected: $selected /}
+ {param spritemap: $spritemap /}
+ {param stickerElementClasses: $stickerElementClasses /}
+ {param stickerImageAlt: $stickerImageAlt /}
+ {param stickerImageSrc: $stickerImageSrc /}
+ {param stickerLabel: $stickerLabel /}
+ {param stickerShape: $stickerShape /}
+ {param stickerStyle: $stickerStyle /}
+ {/call}
+
+{/template}
+
+/**
+ * This renders the content of the row.
+ */
+{template .content}
+ {@param spritemap: string}
+ {@param? actionColumnElementClasses: string}
+ {@param? actionItems: list>}
+ {@param? columns: list>}
+ {@param? contentRenderer: string}
+ {@param? disabled: bool}
+ {@param? handleItemToggled_: any}
+ {@param? inputName: string}
+ {@param? inputValue: string}
+ {@param? selectable: bool}
+ {@param? selectableElementClasses: string}
+ {@param? selected: bool}
+ {@param? stickerElementClasses: string}
+ {@param? stickerImageAlt: string}
+ {@param? stickerImageSrc: string}
+ {@param? stickerLabel: string}
+ {@param? stickerShape: string}
+ {@param? stickerStyle: string}
+
+ {if $selectable}
+
+ {call ClayCheckbox.render}
+ {param checked: $selected /}
+ {param disabled: $disabled /}
+ {param events: ['change': $handleItemToggled_] /}
+ {param hideLabel: true /}
+ {param name: $inputName /}
+ {param value: $inputValue /}
+ {/call}
+
+ {/if}
+
+ {if $stickerLabel or $stickerImageSrc}
+
+ {if $stickerImageSrc}
+ {call ClaySticker.render}
+ {param imageAlt: $stickerImageAlt /}
+ {param imageSrc: $stickerImageSrc /}
+ {param shape: $stickerShape ?: 'circle' /}
+ {/call}
+ {else}
+ {call ClaySticker.render}
+ {param label: $stickerLabel /}
+ {param shape: $stickerShape ?: 'circle' /}
+ {param style: $stickerStyle /}
+ {/call}
+ {/if}
+
+ {/if}
+
+ {if $columns}
+ {foreach $column in $columns}
+ {delcall ClayTableItem.Column variant="$contentRenderer"}
+ {param buttonStyle: $column.buttonStyle /}
+ {param elementClasses: $column.elementClasses /}
+ {param href: $column.href /}
+ {param label: $column.label /}
+ {param labelStyle: $column.labelStyle /}
+ {param progressBar: $column.progressBar /}
+ {param type: $column.type ?: 'text' /}
+ {param useEllipse: $column.useEllipse /}
+ {/delcall}
+ {/foreach}
+ {/if}
+
+ {if $actionItems}
+
+ {call .quickMenu}
+ {param actionItems: $actionItems /}
+ {param spritemap: $spritemap /}
+ {/call}
+
+ {call ClayActionsDropdown.render}
+ {param items: $actionItems /}
+ {param spritemap: $spritemap /}
+ {/call}
+
+ {/if}
+{/template}
+
+/**
+ * This renders a multiples columns of the row.
+ */
+{deltemplate ClayTableItem.Column}
+ {@param? buttonStyle: string}
+ {@param? elementClasses: string}
+ {@param? href: string}
+ {@param? label: string}
+ {@param? labelStyle: string}
+ {@param? progressBar: [
+ maxValue: int,
+ minValue: int,
+ status: string,
+ value: int
+ ]}
+ {@param? type: string}
+ {@param? useEllipse: bool}
+
+ {let $labelContent kind="html"}
+ {call .label}
+ {param href: $href /}
+ {param label: $label /}
+ {/call}
+ {/let}
+
+ {let $content kind="html"}
+ {if $type == 'label'}
+ {call ClayLabel.render}
+ {param label: $label /}
+ {param style: $labelStyle /}
+ {/call}
+ {elseif $progressBar}
+ {call ClayProgressBar.render}
+ {param maxValue: $progressBar.maxValue /}
+ {param minValue: $progressBar.minValue /}
+ {param status: $progressBar.status /}
+ {param value: $progressBar.value /}
+ {/call}
+ {elseif $type == 'button'}
+ {call ClayButton.render}
+ {param label: $label /}
+ {param size: 'sm' /}
+ {param style: $labelStyle /}
+ {/call}
+ {elseif $type == 'text'}
+ {if $useEllipse}
+ {$labelContent}
+ {else}
+ {$labelContent}
+ {/if}
+ {/if}
+ {/let}
+
+ {let $classes kind="text"}
+ {if $elementClasses}
+ {$elementClasses}
+ {/if}
+
+ {if $useEllipse}
+ {sp}table-cell-expand
+ {/if}
+ {/let}
+
+
+ {$content}
+
+{/deltemplate}
+
+/**
+ * This renders a text of the column.
+ */
+{template .label}
+ {@param? href: string}
+ {@param? label: string}
+
+ {if $label and $href}
+ {call ClayLink.render}
+ {param href: $href /}
+ {param label: $label /}
+ {/call}
+ {else}
+ {$label}
+ {/if}
+{/template}
+
+/**
+ * This renders the quick actions menu.
+ */
+{template .quickMenu}
+ {@param actionItems: list>}
+ {@param spritemap: string}
+
+
+{/template}
diff --git a/packages/clay-table/src/__tests__/ClayTable.js b/packages/clay-table/src/__tests__/ClayTable.js
new file mode 100644
index 000000000..528cf83a3
--- /dev/null
+++ b/packages/clay-table/src/__tests__/ClayTable.js
@@ -0,0 +1,248 @@
+import ClayTable from '../ClayTable';
+
+let component;
+let spritemap = 'icons.svg';
+let items = [
+ {
+ columns: [
+ {
+ href: '#1',
+ label: 'suffing-photo.png',
+ useEllipse: true,
+ },
+ {
+ label: 'Juan Anton',
+ },
+ {
+ label: '264KB',
+ },
+ {
+ label: 'Approved',
+ labelStyle: 'success',
+ type: 'label',
+ },
+ {
+ label: '15 Minutes Ago',
+ },
+ {
+ label: '15 Minutes Ago',
+ },
+ ],
+ },
+ {
+ columns: [
+ {
+ href: '#1',
+ label: 'suffing-photo.png',
+ useEllipse: true,
+ },
+ {
+ label: 'Juan Anton',
+ },
+ {
+ label: '264KB',
+ },
+ {
+ label: 'Approved',
+ labelStyle: 'success',
+ type: 'label',
+ },
+ {
+ label: '15 Minutes Ago',
+ },
+ {
+ label: '15 Minutes Ago',
+ },
+ ],
+ },
+];
+
+describe('ClayTable', function() {
+ afterEach(() => {
+ if (component) {
+ component.dispose();
+ }
+ });
+
+ it('should render the default markup', () => {
+ component = new ClayTable({
+ spritemap: spritemap,
+ });
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('should render a ClayTable with classes', () => {
+ component = new ClayTable({
+ elementClasses: 'my-custom-class',
+ spritemap: spritemap,
+ });
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('should render a ClayTable with size `lg`', () => {
+ component = new ClayTable({
+ size: 'lg',
+ spritemap: spritemap,
+ });
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('should render a ClayTable with size `md`', () => {
+ component = new ClayTable({
+ size: 'md',
+ spritemap: spritemap,
+ });
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('should render a ClayTable with size `sm`', () => {
+ component = new ClayTable({
+ size: 'sm',
+ spritemap: spritemap,
+ });
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('should render a ClayTable with size `xl`', () => {
+ component = new ClayTable({
+ size: 'xl',
+ spritemap: spritemap,
+ });
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('should render a ClayTable with id', () => {
+ component = new ClayTable({
+ id: 'myId',
+ spritemap: spritemap,
+ });
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('should render a ClayTable with multiples items', () => {
+ component = new ClayTable({
+ items: items,
+ spritemap: spritemap,
+ });
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('should render a ClayTable with multiples columns in header', () => {
+ component = new ClayTable({
+ header: [
+ {
+ label: 'Title',
+ },
+ {
+ label: 'Author',
+ },
+ {
+ label: 'Size',
+ },
+ {
+ label: 'Status',
+ },
+ ],
+ spritemap: spritemap,
+ });
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('should render a ClayTable with colspan in columns header', () => {
+ component = new ClayTable({
+ header: [
+ {
+ colSpan: 2,
+ label: 'Foo',
+ },
+ {
+ label: 'Bar',
+ },
+ ],
+ spritemap: spritemap,
+ });
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('should render a ClayTable with elementClasses in the columns', () => {
+ component = new ClayTable({
+ header: [
+ {
+ elementClasses: 'custom1-column',
+ label: 'Foo',
+ },
+ {
+ elementClasses: 'custom2-column',
+ label: 'Bar',
+ },
+ ],
+ items: [
+ {
+ columns: [
+ {
+ elementClasses: 'custom1-column',
+ label: 'Foo',
+ },
+ {
+ elementClasses: 'custom2-column',
+ label: 'Bar',
+ },
+ ],
+ },
+ ],
+ spritemap: spritemap,
+ });
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('should render the ClayTable with group', () => {
+ component = new ClayTable({
+ items: [
+ {
+ items: [
+ {
+ columns: [
+ {
+ label: 'Foo',
+ },
+ ],
+ },
+ ],
+ group: 'Group 1',
+ },
+ {
+ items: [
+ {
+ columns: [
+ {
+ label: 'Foo',
+ },
+ ],
+ },
+ ],
+ group: 'Group 2',
+ },
+ ],
+ spritemap: spritemap,
+ });
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('should fail when no spritemap is passed', () => {
+ expect(() => {
+ component = new ClayTable();
+ }).toThrow();
+ });
+});
diff --git a/packages/clay-table/src/__tests__/ClayTableItem.js b/packages/clay-table/src/__tests__/ClayTableItem.js
new file mode 100644
index 000000000..6318a3c4c
--- /dev/null
+++ b/packages/clay-table/src/__tests__/ClayTableItem.js
@@ -0,0 +1,452 @@
+import ClayTableItem from '../ClayTableItem';
+
+let component;
+let spritemap = 'icons.svg';
+
+describe('ClayTableItem', function() {
+ afterEach(() => {
+ if (component) {
+ component.dispose();
+ }
+ });
+
+ it('should render the default markup', () => {
+ component = new ClayTableItem({
+ spritemap: spritemap,
+ });
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('should render the ClayTableItem with id', () => {
+ component = new ClayTableItem({
+ id: 'myId',
+ spritemap: spritemap,
+ });
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('should render the ClayTableItem with custom element class', () => {
+ component = new ClayTableItem({
+ elementClasses: 'my-custom-class',
+ spritemap: spritemap,
+ });
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('should render the ClayTableItem with columns', () => {
+ component = new ClayTableItem({
+ columns: [
+ {
+ label: 'Foo',
+ useEllipse: true,
+ },
+ {
+ label: 'Bar',
+ url: '#1',
+ },
+ {
+ label: 'Foo',
+ },
+ {
+ label: 'Bar',
+ },
+ ],
+ spritemap: spritemap,
+ });
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('should render the ClayTableItem with user sticker in the column', () => {
+ component = new ClayTableItem({
+ columns: [
+ {
+ label: 'Name',
+ useEllipse: true,
+ },
+ ],
+ spritemap: spritemap,
+ stickerLabel: 'AA',
+ stickerStyle: 'primary',
+ });
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('should render the ClayTableItem with custom classes in column of sticker', () => {
+ component = new ClayTableItem({
+ columns: [
+ {
+ label: 'Name',
+ useEllipse: true,
+ },
+ ],
+ spritemap: spritemap,
+ stickerElementClasses: 'custom-column',
+ stickerLabel: 'AA',
+ stickerStyle: 'primary',
+ });
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('should render ClayTableItem with sticker with image in column', () => {
+ component = new ClayTableItem({
+ columns: [
+ {
+ label: 'Name',
+ useEllipse: true,
+ },
+ ],
+ spritemap: spritemap,
+ stickerImageSrc: 'image.png',
+ stickerImageAlt: 'Image',
+ });
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('should render ClayTableItem with sticker shape `rounded`', () => {
+ component = new ClayTableItem({
+ columns: [
+ {
+ label: 'Name',
+ useEllipse: true,
+ },
+ ],
+ spritemap: spritemap,
+ stickerImageSrc: 'image.png',
+ stickerImageAlt: 'Image',
+ stickerShape: 'rounded',
+ });
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('should render the ClayTableItem with progress bar in the column', () => {
+ component = new ClayTableItem({
+ columns: [
+ {
+ progressBar: {
+ value: 40,
+ },
+ },
+ ],
+ spritemap: spritemap,
+ });
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('should render the ClayTableItem with label in the column', () => {
+ component = new ClayTableItem({
+ columns: [
+ {
+ label: 'Approved',
+ labelStyle: 'success',
+ type: 'label',
+ },
+ ],
+ spritemap: spritemap,
+ });
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('should render the ClayTableItem with action menu', () => {
+ component = new ClayTableItem({
+ actionItems: [
+ {
+ label: 'Option 1',
+ href: '#1',
+ },
+ {
+ label: 'Option 2',
+ separator: true,
+ href: '#2',
+ },
+ {
+ label: 'Option 3',
+ href: '#3',
+ },
+ ],
+ spritemap: spritemap,
+ });
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('should render the ClayTableItem with custom classes in column of `action menu`', () => {
+ component = new ClayTableItem({
+ actionItems: [
+ {
+ label: 'Option 1',
+ href: '#1',
+ },
+ {
+ label: 'Option 2',
+ separator: true,
+ href: '#2',
+ },
+ {
+ label: 'Option 3',
+ href: '#3',
+ },
+ ],
+ actionColumnElementClasses: 'custom-column',
+ spritemap: spritemap,
+ });
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('should render the ClayTableItem with quick action menu', () => {
+ component = new ClayTableItem({
+ actionItems: [
+ {
+ icon: 'trash',
+ label: 'Option 1',
+ quickAction: true,
+ href: '#1',
+ },
+ {
+ icon: 'download',
+ label: 'Option 2',
+ quickAction: true,
+ separator: true,
+ href: '#2',
+ },
+ {
+ icon: 'info-circle-open',
+ label: 'Option 3',
+ quickAction: true,
+ href: '#3',
+ },
+ ],
+ spritemap: spritemap,
+ });
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('should render the ClayTableItem selectable', () => {
+ component = new ClayTableItem({
+ columns: [
+ {
+ label: 'Foo',
+ useEllipse: true,
+ },
+ {
+ label: 'Bar',
+ href: '#1',
+ },
+ {
+ label: 'Foo',
+ },
+ {
+ label: 'Bar',
+ },
+ ],
+ selectable: true,
+ spritemap: spritemap,
+ });
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('should render the ClayTableItem with custom classes in columns of selectable', () => {
+ component = new ClayTableItem({
+ columns: [
+ {
+ label: 'Foo',
+ useEllipse: true,
+ },
+ {
+ label: 'Bar',
+ href: '#1',
+ },
+ {
+ label: 'Foo',
+ },
+ {
+ label: 'Bar',
+ },
+ ],
+ selectable: true,
+ selectableElementClasses: 'custom-column',
+ spritemap: spritemap,
+ });
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('should render the ClayTableItem selected', () => {
+ component = new ClayTableItem({
+ columns: [
+ {
+ label: 'Foo',
+ useEllipse: true,
+ },
+ {
+ label: 'Bar',
+ href: '#1',
+ },
+ {
+ label: 'Foo',
+ },
+ {
+ label: 'Bar',
+ },
+ ],
+ selectable: true,
+ selected: true,
+ spritemap: spritemap,
+ });
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('should render the ClayTableItem disabled', () => {
+ component = new ClayTableItem({
+ columns: [
+ {
+ label: 'Foo',
+ useEllipse: true,
+ },
+ {
+ label: 'Bar',
+ href: '#1',
+ },
+ {
+ label: 'Foo',
+ },
+ {
+ label: 'Bar',
+ },
+ ],
+ selectable: true,
+ disabled: true,
+ spritemap: spritemap,
+ });
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('should render the ClayTableItem with input name', () => {
+ component = new ClayTableItem({
+ columns: [
+ {
+ label: 'Foo',
+ useEllipse: true,
+ },
+ {
+ label: 'Bar',
+ href: '#1',
+ },
+ {
+ label: 'Foo',
+ },
+ {
+ label: 'Bar',
+ },
+ ],
+ inputName: 'name',
+ selectable: true,
+ spritemap: spritemap,
+ });
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('should render the ClayTableItem with input value', () => {
+ component = new ClayTableItem({
+ columns: [
+ {
+ label: 'Foo',
+ useEllipse: true,
+ },
+ {
+ label: 'Bar',
+ href: '#1',
+ },
+ {
+ label: 'Foo',
+ },
+ {
+ label: 'Bar',
+ },
+ ],
+ inputValue: 'value',
+ selectable: true,
+ spritemap: spritemap,
+ });
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('should render a selectable ClayTableItem and emit an event on itemToggle', () => {
+ component = new ClayTableItem({
+ columns: [
+ {
+ label: 'Foo',
+ },
+ {
+ label: 'Bar',
+ href: '#1',
+ },
+ {
+ label: 'Foo',
+ },
+ {
+ label: 'Bar',
+ },
+ ],
+ selectable: true,
+ spritemap: spritemap,
+ });
+
+ const spy = jest.spyOn(component, 'emit');
+
+ component.element.querySelector('input[type="checkbox"]').click();
+
+ expect(spy).toHaveBeenCalled();
+ expect(spy).toHaveBeenCalledWith('itemToggled', expect.any(Object));
+ });
+
+ it('should render the ClayTableItem with button', () => {
+ component = new ClayTableItem({
+ columns: [
+ {
+ label: 'Foo',
+ useEllipse: true,
+ },
+ {
+ label: 'Bar',
+ href: '#1',
+ },
+ {
+ label: 'Foo',
+ },
+ {
+ label: 'Bar',
+ buttonStyle: 'primary',
+ type: 'button',
+ },
+ ],
+ inputValue: 'value',
+ selectable: true,
+ spritemap: spritemap,
+ });
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('should fail when no spritemap is passed', () => {
+ expect(() => {
+ component = new ClayTableItem();
+ }).toThrow();
+ });
+});
diff --git a/packages/clay-table/src/__tests__/__snapshots__/ClayTable.js.snap b/packages/clay-table/src/__tests__/__snapshots__/ClayTable.js.snap
new file mode 100644
index 000000000..72c30f3d8
--- /dev/null
+++ b/packages/clay-table/src/__tests__/__snapshots__/ClayTable.js.snap
@@ -0,0 +1,148 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`ClayTable should render a ClayTable with classes 1`] = `
+
+`;
+
+exports[`ClayTable should render a ClayTable with colspan in columns header 1`] = `
+
+`;
+
+exports[`ClayTable should render a ClayTable with elementClasses in the columns 1`] = `
+
+
+
+
+ Foo
+ Bar
+
+
+
+
+ Foo
+ Bar
+
+
+
+
+`;
+
+exports[`ClayTable should render a ClayTable with id 1`] = `
+
+`;
+
+exports[`ClayTable should render a ClayTable with multiples columns in header 1`] = `
+
+
+
+
+ Title
+ Author
+ Size
+ Status
+
+
+
+
+`;
+
+exports[`ClayTable should render a ClayTable with multiples items 1`] = `
+
+
+
+
+
+
+ suffing-photo.png
+
+
+ Juan Anton
+ 264KB
+
+ Approved
+
+ 15 Minutes Ago
+ 15 Minutes Ago
+
+
+
+
+ suffing-photo.png
+
+
+ Juan Anton
+ 264KB
+
+ Approved
+
+ 15 Minutes Ago
+ 15 Minutes Ago
+
+
+
+
+`;
+
+exports[`ClayTable should render a ClayTable with size \`lg\` 1`] = `
+
+`;
+
+exports[`ClayTable should render a ClayTable with size \`md\` 1`] = `
+
+`;
+
+exports[`ClayTable should render a ClayTable with size \`sm\` 1`] = `
+
+`;
+
+exports[`ClayTable should render a ClayTable with size \`xl\` 1`] = `
+
+`;
+
+exports[`ClayTable should render the ClayTable with group 1`] = `
+
+
+
+
+ Group 1
+
+
+ Foo
+
+
+ Group 2
+
+
+ Foo
+
+
+
+
+`;
+
+exports[`ClayTable should render the default markup 1`] = `
+
+`;
diff --git a/packages/clay-table/src/__tests__/__snapshots__/ClayTableItem.js.snap b/packages/clay-table/src/__tests__/__snapshots__/ClayTableItem.js.snap
new file mode 100644
index 000000000..3fe6c52e8
--- /dev/null
+++ b/packages/clay-table/src/__tests__/__snapshots__/ClayTableItem.js.snap
@@ -0,0 +1,352 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`ClayTableItem should render ClayTableItem with sticker shape \`rounded\` 1`] = `
+
+
+
+
+
+
+
+ Name
+
+
+`;
+
+exports[`ClayTableItem should render ClayTableItem with sticker with image in column 1`] = `
+
+
+
+
+
+
+
+ Name
+
+
+`;
+
+exports[`ClayTableItem should render the ClayTableItem disabled 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+ Foo
+
+
+ Bar
+
+ Foo
+ Bar
+
+`;
+
+exports[`ClayTableItem should render the ClayTableItem selectable 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+ Foo
+
+
+ Bar
+
+ Foo
+ Bar
+
+`;
+
+exports[`ClayTableItem should render the ClayTableItem selected 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+ Foo
+
+
+ Bar
+
+ Foo
+ Bar
+
+`;
+
+exports[`ClayTableItem should render the ClayTableItem with action menu 1`] = `
+
+
+
+
+
+
+ ellipsis-v
+
+
+
+
+
+
+
+`;
+
+exports[`ClayTableItem should render the ClayTableItem with button 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+ Foo
+
+
+ Bar
+
+ Foo
+
+ Bar
+
+
+`;
+
+exports[`ClayTableItem should render the ClayTableItem with columns 1`] = `
+
+
+ Foo
+
+ Bar
+ Foo
+ Bar
+
+`;
+
+exports[`ClayTableItem should render the ClayTableItem with custom classes in column of \`action menu\` 1`] = `
+
+
+
+
+
+
+ ellipsis-v
+
+
+
+
+
+
+
+`;
+
+exports[`ClayTableItem should render the ClayTableItem with custom classes in column of sticker 1`] = `
+
+
+ AA
+
+
+ Name
+
+
+`;
+
+exports[`ClayTableItem should render the ClayTableItem with custom classes in columns of selectable 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+ Foo
+
+
+ Bar
+
+ Foo
+ Bar
+
+`;
+
+exports[`ClayTableItem should render the ClayTableItem with custom element class 1`] = ` `;
+
+exports[`ClayTableItem should render the ClayTableItem with id 1`] = ` `;
+
+exports[`ClayTableItem should render the ClayTableItem with input name 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+ Foo
+
+
+ Bar
+
+ Foo
+ Bar
+
+`;
+
+exports[`ClayTableItem should render the ClayTableItem with input value 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+ Foo
+
+
+ Bar
+
+ Foo
+ Bar
+
+`;
+
+exports[`ClayTableItem should render the ClayTableItem with label in the column 1`] = `
+
+
+ Approved
+
+
+`;
+
+exports[`ClayTableItem should render the ClayTableItem with progress bar in the column 1`] = `
+
+
+
+
+
+`;
+
+exports[`ClayTableItem should render the ClayTableItem with quick action menu 1`] = `
+
+
+
+
+
+
+ ellipsis-v
+
+
+
+
+
+
+
+`;
+
+exports[`ClayTableItem should render the ClayTableItem with user sticker in the column 1`] = `
+
+
+ AA
+
+
+ Name
+
+
+`;
+
+exports[`ClayTableItem should render the default markup 1`] = ` `;
diff --git a/packages/clay-table/src/items_validator.js b/packages/clay-table/src/items_validator.js
new file mode 100644
index 000000000..1478b49b8
--- /dev/null
+++ b/packages/clay-table/src/items_validator.js
@@ -0,0 +1,69 @@
+import {Config} from 'metal-state';
+
+let actionItems = {
+ disabled: Config.bool().value(false),
+ icon: Config.string(),
+ label: Config.string(),
+ quickAction: Config.bool().value(false),
+ separator: Config.bool().value(false),
+ href: Config.string().required(),
+};
+
+let columns = {
+ buttonStyle: Config.oneOf(['link', 'primary', 'secondary']).value(
+ 'primary'
+ ),
+ elementClasses: Config.string(),
+ href: Config.string(),
+ label: Config.string(),
+ labelStyle: Config.oneOf([
+ 'danger',
+ 'info',
+ 'secondary',
+ 'success',
+ 'warning',
+ ]).value('secondary'),
+ progressBar: Config.shapeOf({
+ maxValue: Config.number(),
+ minValue: Config.number(),
+ status: Config.oneOf(['complete', 'warning']),
+ value: Config.number(),
+ }),
+ type: Config.oneOf(['text', 'button', 'label']).value('text'),
+ useEllipse: Config.bool().value(false),
+};
+
+let items = {
+ actionColumnElementClasses: Config.string(),
+ actionItems: Config.arrayOf(Config.shapeOf(actionItems)),
+ columns: Config.arrayOf(Config.shapeOf(columns)),
+ disabled: Config.bool().value(false),
+ group: Config.string(),
+ inputName: Config.string(),
+ inputValue: Config.string(),
+ selectable: Config.bool().value(false),
+ selectableElementClasses: Config.string(),
+ selected: Config.bool().value(false),
+ stickerElementClasses: Config.string(),
+ stickerImageAlt: Config.string(),
+ stickerImageSrc: Config.string(),
+ stickerLabel: Config.string(),
+ stickerShape: Config.string().value('circle'),
+ stickerStyle: Config.oneOf([
+ 'danger',
+ 'dark',
+ 'info',
+ 'light',
+ 'primary',
+ 'secondary',
+ 'success',
+ 'warning',
+ ]).value('primary'),
+};
+
+const actionsItemsValidator = Config.arrayOf(Config.shapeOf(actionItems));
+const columnsValidator = Config.arrayOf(Config.shapeOf(columns));
+const itemsValidator = Config.arrayOf(Config.shapeOf(items));
+
+export {actionsItemsValidator, columnsValidator, itemsValidator};
+export default itemsValidator;
diff --git a/packages/clay-table/webpack.config.js b/packages/clay-table/webpack.config.js
new file mode 100644
index 000000000..63267c1da
--- /dev/null
+++ b/packages/clay-table/webpack.config.js
@@ -0,0 +1,31 @@
+const path = require('path');
+const webpack = require('webpack');
+
+module.exports = {
+ entry: './src/ClayTable.js',
+ module: {
+ rules: [
+ {
+ test: /\.js$/,
+ exclude: /(node_modules|bower_components)/,
+ use: {
+ loader: 'babel-loader',
+ options: {
+ compact: false,
+ presets: ['babel-preset-env'],
+ plugins: ['babel-plugin-transform-node-env-inline'],
+ },
+ },
+ },
+ ],
+ },
+ output: {
+ library: 'metal',
+ libraryTarget: 'this',
+ filename: './build/globals/clay-table.js',
+ },
+ plugins: [new webpack.optimize.ModuleConcatenationPlugin()],
+ resolve: {
+ mainFields: ['esnext:main', 'main'],
+ },
+};