diff --git a/packages/clay-list/demos/index.html b/packages/clay-list/demos/index.html index 2048d2f0d..efa173b3d 100644 --- a/packages/clay-list/demos/index.html +++ b/packages/clay-list/demos/index.html @@ -73,53 +73,23 @@

Selectable List with Label

-
-
-

Selectable List with Action Menu

-
-
-
-

Selectable List with Quick Action Menu

-
-
-
- -
-
-

Selectable List with Header Title

-
+

Selectable List with Selected Items

-
+
diff --git a/packages/clay-list/src/ClayList.js b/packages/clay-list/src/ClayList.js index 3f1c88571..f38f855a2 100644 --- a/packages/clay-list/src/ClayList.js +++ b/packages/clay-list/src/ClayList.js @@ -1,14 +1,15 @@ +import 'clay-checkbox'; import 'clay-dropdown'; import 'clay-icon'; import 'clay-label'; import 'clay-link'; import 'clay-sticker'; -import './ClayListItem'; - +// eslint-disable-next-line +import { ClayActionsDropdown } from 'clay-dropdown'; +import {Config} from 'metal-state'; import Component from 'metal-component'; import defineWebComponent from 'metal-web-component'; import Soy from 'metal-soy'; -import {Config} from 'metal-state'; import templates from './ClayList.soy.js'; @@ -54,41 +55,10 @@ ClayList.STATE = { * List of items. * @instance * @memberof ClayList - * @type {!array} + * @type {?array|undefined} * @default undefined */ - items: Config.arrayOf( - Config.shapeOf({ - actionItems: Config.arrayOf( - Config.shapeOf({ - disabled: Config.bool().value(false), - href: Config.string().required(), - icon: Config.string(), - label: Config.string().required(), - quickAction: Config.bool(), - separator: Config.bool().value(false), - }) - ), - description: Config.string(), - href: Config.string(), - icon: Config.string(), - iconShape: Config.oneOf(['circle', 'rounded']).value('rounded'), - labels: Config.arrayOf( - Config.shapeOf({ - label: Config.string(), - style: Config.oneOf([ - 'danger', - 'info', - 'secondary', - 'success', - 'warning', - ]).value('secondary'), - }) - ), - selected: Config.bool().value(false), - title: Config.string().required(), - }) - ).required(), + items: Config.array(), /** * Flag to indicate if the list group items are selectable. @@ -100,22 +70,31 @@ ClayList.STATE = { selectable: Config.bool().value(false), /** - * The path to the SVG spritemap file containing the icons. + * Schema mapping list item fields with item data properties. * @instance * @memberof ClayList - * @type {?string|undefined} + * @type {!object} * @default undefined */ - spritemap: Config.string(), + schema: Config.arrayOf( + Config.shapeOf({ + contentRenderer: Config.string(), + fieldName: Config.string(), + fieldsMap: Config.object(), + iconsMap: Config.object(), + iconShapesMap: Config.object(), + labelStylesMap: Config.object(), + }) + ).required(), /** - * Header of the list group. + * The path to the SVG spritemap file containing the icons. * @instance * @memberof ClayList * @type {?string|undefined} * @default undefined */ - title: Config.string(), + spritemap: Config.string(), }; defineWebComponent('clay-list', ClayList); diff --git a/packages/clay-list/src/ClayList.soy b/packages/clay-list/src/ClayList.soy index 830634e3d..1175556f2 100644 --- a/packages/clay-list/src/ClayList.soy +++ b/packages/clay-list/src/ClayList.soy @@ -4,32 +4,20 @@ * This renders the component's whole content. */ {template .render} - {@param items: list<[ - actionItems: list<[ - disabled: bool, - href: string, - icon: string, - label: string, - quickAction: bool, - separator: bool - ]>, - description: string, - href: string, - icon: string, - iconShape: string, - labels: list<[ - label: string, - style: string - ]>, - selected: bool, - title: string + {@param schema: list<[ + contentRenderer: string, + fieldName: string, + fieldsMap: ?, + iconsMap: ?, + iconShapesMap: ?, + labelStylesMap: ? ]>} {@param? elementClasses: string} {@param? handleItemToggled_: any} {@param? id: string} + {@param? items: list} {@param? selectable: bool} {@param? spritemap: string} - {@param? title: string} {let $attributes kind="attributes"} class="list-group show-quick-actions-on-hover @@ -44,26 +32,241 @@ {/let} +{/template} + +{template .item} + {@param item: ?} + {@param schema: list<[ + contentRenderer: string, + fieldName: string, + fieldsMap: ?, + iconsMap: ?, + iconShapesMap: ?, + labelStylesMap: ? + ]>} + {@param? handleItemToggled_: any} + {@param? selectable: bool} + {@param? spritemap: string} + + {let $listItemClasses kind="text"} + list-group-item list-group-item-flex + {if $item.selected} + {sp}active + {/if} + {/let} + +
  • + {if $selectable} +
    + {call ClayCheckbox.render} + {param checked: $item.selected /} + {param events: ['change': $handleItemToggled_] /} + {param hideLabel: true /} + {param label: 'select' /} + {/call} +
    + {/if} + + {foreach $fieldSchema in $schema} + {delcall ClayList.Field variant="$fieldSchema.contentRenderer"} + {param fieldSchema: $fieldSchema /} + {param item: $item /} + {param spritemap: $spritemap /} + {param value: $item[$fieldSchema.fieldName] /} + {/delcall} + {/foreach} + + {if $item.actionItems and $spritemap} +
    + {call .quickMenu} + {param items: $item.actionItems /} + {param spritemap: $spritemap /} + {/call} + + {call ClayActionsDropdown.render} + {param items: $item.actionItems /} + {param spritemap: $spritemap /} + {/call} +
    + {/if} +
  • +{/template} + +/** + * This renders all the items in the list, iteraing over the items and its + * possible nested items. + */ +{template .items} + {@param items: list} + {@param schema: list<[ + contentRenderer: string, + fieldName: string, + fieldsMap: ?, + iconsMap: ?, + iconShapesMap: ?, + labelStylesMap: ? + ]>} + {@param? handleItemToggled_: any} + {@param? selectable: bool} + {@param? spritemap: string} + + {foreach $item in $items} + {if $item.items}
  • -

    {$title}

    +

    {$item.label}

  • - {/if} - {foreach $item in $items} - {call ClayListItem.render} - {param actionItems: $item.actionItems /} - {param description: $item.description /} - {param events: ['itemToggled': $handleItemToggled_ ] /} - {param href: $item.href /} - {param icon: $item.icon /} - {param iconShape: $item.iconShape /} - {param labels: $item.labels /} + {call .items} + {param handleItemToggled_: $handleItemToggled_ /} + {param items: $item.items /} + {param schema: $schema /} + {param selectable: $selectable /} + {param spritemap: $spritemap /} + {/call} + {else} + {call .item} + {param handleItemToggled_: $handleItemToggled_ /} + {param item: $item /} + {param schema: $schema /} {param selectable: $selectable /} - {param selected: $item.selected /} {param spritemap: $spritemap /} - {param title: $item.title /} {/call} + {/if} + {/foreach} +{/template} + +/** + * This renders the quick actions menu + */ +{template .quickMenu} + {@param items: list<[ + disabled: bool, + href: string, + icon: string, + label: string, + quickAction: bool, + separator: bool + ]>} + {@param spritemap: string} + +
    + {foreach $item in $items} + {if $item.quickAction and $item.icon and $spritemap} + {call ClayLink.render} + {param elementClasses: 'quick-action-item' /} + {param href: $item.href /} + {param icon: $item.icon /} + {param spritemap: $spritemap /} + {/call} + {/if} {/foreach} - -{/template} \ No newline at end of file +
    +{/template} + +/** + * This renders the content of the item. + */ +{deltemplate ClayList.Field variant="'content'"} + {@param fieldSchema: [ + contentRenderer: string, + fieldName: string, + fieldsMap: ?, + iconsMap: ?, + iconShapesMap: ?, + labelStylesMap: ? + ]} + {@param item: ?} + {@param value: ?} + {@param? spritemap: string} + +
    +

    + {if $fieldSchema.fieldsMap and $fieldSchema.fieldsMap.href and $item[$fieldSchema.fieldsMap.href]} + {call ClayLink.render} + {param href: $item[$fieldSchema.fieldsMap.href] /} + {param label: $item[$fieldSchema.fieldsMap.title] /} + {/call} + {else} + {$item[$fieldSchema.fieldsMap.title]} + {/if} +

    + + {if $fieldSchema.fieldsMap and $fieldSchema.fieldsMap.description and $item[$fieldSchema.fieldsMap.description]} +

    {$item[$fieldSchema.fieldsMap.description]}

    + {/if} + + {if $fieldSchema.fieldsMap and $fieldSchema.fieldsMap.labels and $item[$fieldSchema.fieldsMap.labels]} +
    + {foreach $label in $item[$fieldSchema.fieldsMap.labels]} + {call ClayLabel.render} + {param label: $label /} + {param style: $fieldSchema.labelStylesMap ? $fieldSchema.labelStylesMap[$label] ?: $fieldSchema.labelStylesMap['*'] : null /} + {/call} + {/foreach} +
    + {/if} +
    +{/deltemplate} + +/** + * This renders the icon of the item. + */ +{deltemplate ClayList.Field variant="'icon'"} + {@param fieldSchema: [ + contentRenderer: string, + fieldName: string, + fieldsMap: ?, + iconsMap: ?, + iconShapesMap: ?, + labelStylesMap: ? + ]} + {@param item: ?} + {@param value: ?} + {@param? spritemap: string} + +
    + {if $spritemap} + {call ClaySticker.render} + {param icon: $fieldSchema.iconsMap ? $fieldSchema.iconsMap[$value] ?: $fieldSchema.iconsMap['*'] : $value /} + {param shape: $fieldSchema.iconShapesMap ? $fieldSchema.iconShapesMap[$value] ?: $fieldSchema.iconShapesMap['*'] : null /} + {param spritemap: $spritemap /} + {/call} + {/if} +
    +{/deltemplate} + +/** + * This renders a simple content of the item. + */ +{deltemplate ClayList.Field variant="'simple'"} + {@param fieldSchema: [ + contentRenderer: string, + fieldName: string, + fieldsMap: ?, + iconsMap: ?, + iconShapesMap: ?, + labelStylesMap: ? + ]} + {@param item: ?} + {@param value: ?} + {@param? spritemap: string} + + {if $fieldSchema.fieldsMap and $fieldSchema.fieldsMap.href and $item[$fieldSchema.fieldsMap.href]} + {call ClayLink.render} + {param href: $item[$fieldSchema.fieldsMap.href] /} + {param label: $item[$fieldSchema.fieldsMap.title] /} + {/call} + {else} + {$item[$fieldSchema.fieldsMap.title]} + {/if} +{/deltemplate} \ No newline at end of file diff --git a/packages/clay-list/src/ClayListItem.js b/packages/clay-list/src/ClayListItem.js deleted file mode 100644 index e3a03702b..000000000 --- a/packages/clay-list/src/ClayListItem.js +++ /dev/null @@ -1,178 +0,0 @@ -import 'clay-checkbox'; -import 'clay-icon'; -import 'clay-label'; -import 'clay-link'; -import 'clay-sticker'; -// eslint-disable-next-line -import { ClayActionsDropdown } from 'clay-dropdown'; -import {Config} from 'metal-state'; -import Component from 'metal-component'; -import defineWebComponent from 'metal-web-component'; -import Soy from 'metal-soy'; - -import templates from './ClayListItem.soy.js'; - -/** - * Metal ClayListItem component. - */ -class ClayListItem extends Component { - /** - * Continues the propagation of the checkbox changed event - * @param {!Event} event - * @private - */ - handleItemCheckboxClick_(event) { - this.emit('itemToggled', event); - } -} - -/** - * State definition. - * @static - * @type {!Object} - */ -ClayListItem.STATE = { - /** - * List of items to display in the actions menu. - * @instance - * @memberof ClayListItem - * @type {!array} - * @default undefined - */ - actionItems: Config.arrayOf( - Config.shapeOf({ - disabled: Config.bool().value(false), - href: Config.string().required(), - icon: Config.string(), - label: Config.string().required(), - quickAction: Config.bool(), - separator: Config.bool().value(false), - }) - ), - - /** - * Name of the content renderer to use template variants. - * @instance - * @memberof ClayListItem - * @type {?string|undefined} - * @default undefined - */ - contentRenderer: Config.string(), - - /** - * Description of the item - * @instance - * @memberof ClayListItem - * @type {?string|undefined} - * @default undefined - */ - description: Config.string(), - - /** - * CSS classes to be applied to the element. - * @instance - * @memberof ClayListItem - * @type {?string|undefined} - * @default undefined - */ - elementClasses: Config.string(), - - /** - * Url of the item. - * @instance - * @memberof ClayListItem - * @type {?string|undefined} - * @default undefined - */ - href: Config.string(), - - /** - * Icon of the list item. - * @instance - * @memberof ClayListItem - * @type {?string|undefined} - * @default undefined - */ - icon: Config.string(), - - /** - * Shape of the icon of the list item. - * @instance - * @memberof ClayListItem - * @type {?string|undefined} - * @default rounded - */ - iconShape: Config.oneOf(['circle', 'rounded']).value('rounded'), - - /** - * Id to be applied to the element. - * @instance - * @memberof ClayListItem - * @type {?string|undefined} - * @default undefined - */ - id: Config.string(), - - /** - * Labels of the list item. - * @instance - * @memberof ClayCard - * @type {?array|undefined} - * @default undefined - */ - labels: Config.arrayOf( - Config.shapeOf({ - label: Config.string(), - style: Config.oneOf([ - 'danger', - 'info', - 'secondary', - 'success', - 'warning', - ]).value('secondary'), - }) - ), - - /** - * Flag to indicate if the list item is selectable. - * @instance - * @memberof ClayListItem - * @type {?bool|undefined} - * @default false - */ - selectable: Config.bool().value(false), - - /** - * Flag to indicate if the list item is selected. - * @instance - * @memberof ClayListItem - * @type {?bool|undefined} - * @default false - */ - selected: Config.bool().value(false), - - /** - * The path to the SVG spritemap file containing the icons. - * @instance - * @memberof ClayListItem - * @type {?string|undefined} - * @default undefined - */ - spritemap: Config.string(), - - /** - * Title of the list item. - * @instance - * @memberof ClayListItem - * @type {?string|undefined} - * @default undefined - */ - title: Config.string().required(), -}; - -defineWebComponent('clay-list-item', ClayListItem); - -Soy.register(ClayListItem, templates); - -export {ClayListItem}; -export default ClayListItem; diff --git a/packages/clay-list/src/ClayListItem.soy b/packages/clay-list/src/ClayListItem.soy deleted file mode 100644 index 5171b76b2..000000000 --- a/packages/clay-list/src/ClayListItem.soy +++ /dev/null @@ -1,203 +0,0 @@ -{namespace ClayListItem} - -/** - * This renders the component's whole content. - */ -{template .render} - {@param title: string} - {@param? actionItems: list<[ - disabled: bool, - href: string, - icon: string, - label: string, - quickAction: bool, - separator: bool - ]>} - {@param? contentRenderer: string} - {@param? description: string} - {@param? elementClasses: string} - {@param? handleItemCheckboxClick_: any} - {@param? href: string} - {@param? icon: string} - {@param? iconShape: string} - {@param? id: string} - {@param? labels: list<[ - label: string, - style: string - ]>} - {@param? selectable: bool} - {@param? selected: bool} - {@param? spritemap: string} - - {let $listItemAttributes kind="attributes"} - class="list-group-item list-group-item-flex - {if $elementClasses} - {sp}{$elementClasses} - {/if} - - {if $selected} - {sp}active - {/if} - " - - {if $id} - id="{$id}" - {/if} - {/let} - -
  • - {let $isSimple: not $description and not $selectable and not $icon and not $actionItems and not $labels/} - - {if $isSimple} - {delcall ClayListItem.Simple variant="$contentRenderer"} - {param href: $href /} - {param title: $title /} - {/delcall} - {else} - {if $selectable} -
    - {call ClayCheckbox.render} - {param checked: $selected /} - {param events: ['change': $handleItemCheckboxClick_] /} - {param hideLabel: true /} - {param label: 'select' /} - {/call} -
    - {/if} - - {if $icon and $spritemap} - {delcall ClayListItem.Icon variant="$contentRenderer"} - {param icon: $icon /} - {param iconShape: $iconShape /} - {param spritemap: $spritemap /} - {/delcall} - {/if} - - {delcall ClayListItem.Content variant="$contentRenderer"} - {param description: $description /} - {param href: $href /} - {param labels: $labels /} - {param spritemap: $spritemap /} - {param title: $title /} - {/delcall} - - {if $actionItems and $spritemap} -
    - {call .quickMenu} - {param items: $actionItems /} - {param spritemap: $spritemap /} - {/call} - - {call ClayActionsDropdown.render} - {param items: $actionItems /} - {param spritemap: $spritemap /} - {/call} -
    - {/if} - {/if} -
  • -{/template} - -/** - * This renders the quick actions menu - */ -{template .quickMenu} - {@param items: list<[ - disabled: bool, - href: string, - icon: string, - label: string, - quickAction: bool, - separator: bool - ]>} - {@param spritemap: string} - -
    - {foreach $item in $items} - {if $item.quickAction and $item.icon and $spritemap} - {call ClayLink.render} - {param elementClasses: 'quick-action-item' /} - {param href: $item.href /} - {param icon: $item.icon /} - {param spritemap: $spritemap /} - {/call} - {/if} - {/foreach} -
    -{/template} - -/** - * This renders the content of the item. - */ -{deltemplate ClayListItem.Content} - {@param title: string} - {@param? description: string} - {@param? href: string} - {@param? labels: list<[ - label: string, - style: string - ]>} - {@param? spritemap: string} - -
    -

    - {if $href} - {call ClayLink.render} - {param href: $href /} - {param label: $title /} - {/call} - {else} - {$title} - {/if} -

    - - {if $description} -

    {$description}

    - {/if} - - {if $labels} -
    - {foreach $label in $labels} - {call ClayLabel.render} - {param label: $label.label /} - {param style: $label.style /} - {/call} - {/foreach} -
    - {/if} -
    -{/deltemplate} - -/** - * This renders the icon of the item. - */ -{deltemplate ClayListItem.Icon} - {@param icon: string} - {@param spritemap: string} - {@param? iconShape: string} - -
    - {call ClaySticker.render} - {param icon: $icon /} - {param shape: $iconShape /} - {param spritemap: $spritemap /} - {/call} -
    -{/deltemplate} - -/** - * This renders a simple item. - */ -{deltemplate ClayListItem.Simple} - {@param title: string} - {@param? href: string} - - {if $href} - {call ClayLink.render} - {param href: $href /} - {param label: $title /} - {/call} - {else} - {$title} - {/if} -{/deltemplate} \ No newline at end of file diff --git a/packages/clay-list/src/__tests__/ClayList.js b/packages/clay-list/src/__tests__/ClayList.js index 2a69ccf39..f22abdb19 100644 --- a/packages/clay-list/src/__tests__/ClayList.js +++ b/packages/clay-list/src/__tests__/ClayList.js @@ -2,6 +2,146 @@ import ClayList from '../ClayList'; let component; +const actionItems = [ + { + href: '#1', + icon: 'trash', + label: 'Option 1', + }, + { + href: '#2', + icon: 'download', + label: 'Option 2', + separator: true, + }, + { + href: '#3', + icon: 'info-circle-open', + label: 'Option 3', + }, +]; + +const actionItemsWithQuickItems = [ + { + href: '#1', + icon: 'trash', + label: 'Option 1', + quickAction: true, + }, + { + href: '#2', + icon: 'download', + label: 'Option 2', + quickAction: true, + separator: true, + }, + { + href: '#3', + icon: 'info-circle-open', + label: 'Option 3', + quickAction: true, + }, +]; + +const sagaItems = [ + { + director: 'George Lucas', + downloadHref: '#', + rating: 10, + releaseDate: 'May 19th 1999', + status: ['Error', 'Pending'], + title: 'Episode I: The Phantom Menace', + }, + { + director: 'George Lucas', + downloadHref: '#', + rating: 50, + releaseDate: 'May 12th 2002', + status: ['Watched'], + title: 'Episode II: Attack of the Clones', + }, + { + director: 'George Lucas', + downloadHref: '#', + rating: 60, + releaseDate: 'May 12th 2005', + status: ['Watched'], + title: 'Episode III: Revenge of the Sith', + }, + { + director: 'George Lucas', + downloadHref: '#', + rating: 90, + releaseDate: 'May 25th 1977', + status: ['Watched'], + title: 'Episode IV: A New Hope', + }, + { + director: 'Irvin Kershner', + downloadHref: '#', + rating: 100, + releaseDate: 'May 21th 1980', + status: ['Watched'], + title: 'Episode V: The Empire Strikes Back', + }, + { + director: 'Richard Marquand', + downloadHref: '#', + rating: 90, + releaseDate: 'May 25th 1983', + status: ['Watched'], + title: 'Episode VI: Return of the Jedi', + }, + { + director: 'J. J. Abrams', + downloadHref: '#', + rating: 70, + releaseDate: 'December 14th 2015', + status: ['Watched'], + title: 'Episode VII: The Force Awakens', + }, + { + director: 'Rian Johnson', + downloadHref: '#', + rating: 0, + releaseDate: 'December 9th 2017', + status: ['Pending'], + title: 'Episode VIII: The Last Jedi', + }, +]; + +const expandedItems = [ + { + director: 'Gareth Edwards', + downloadHref: '#', + rating: 70, + releaseDate: 'December 10th 2016', + status: ['Watched'], + title: 'Rogue One: A Star Wars Story', + }, + { + director: 'Ron Howard', + downloadHref: '#', + rating: 0, + releaseDate: 'May 25th 2018', + status: ['Pending'], + title: 'Solo: A Star Wars Story', + }, +]; + +const groupedItems = [ + { + items: sagaItems, + label: 'Saga', + }, + { + items: expandedItems, + label: 'Expanded Universe', + }, +]; + +const spritemap = '../node_modules/lexicon-ux/build/images/icons/icons.svg'; + describe('ClayList', function() { afterEach(() => { if (component) { @@ -11,7 +151,7 @@ describe('ClayList', function() { it('should render the default markup', () => { component = new ClayList({ - items: [], + schema: [], }); expect(component).toMatchSnapshot(); @@ -20,7 +160,7 @@ describe('ClayList', function() { it('should render a ClayList with classes', () => { component = new ClayList({ elementClasses: 'my-custom-class', - items: [], + schema: [], }); expect(component).toMatchSnapshot(); @@ -29,29 +169,107 @@ describe('ClayList', function() { it('should render a ClayList with id', () => { component = new ClayList({ id: 'myId', - items: [], + schema: [], }); expect(component).toMatchSnapshot(); }); - it('should render a selectable ClayList', () => { + it('should render a ClayList with simple items', () => { + component = new ClayList({ + items: sagaItems, + schema: [ + { + contentRenderer: 'simple', + fieldsMap: { + title: 'title', + }, + }, + ], + }); + + expect(component).toMatchSnapshot(); + }); + + it('should render a ClayList with simple items with links', () => { + component = new ClayList({ + items: sagaItems, + schema: [ + { + contentRenderer: 'simple', + fieldsMap: { + href: 'downloadHref', + title: 'title', + }, + }, + ], + }); + + expect(component).toMatchSnapshot(); + }); + + it('should render a ClayList with items', () => { + component = new ClayList({ + items: sagaItems, + schema: [ + { + contentRenderer: 'content', + fieldsMap: { + title: 'title', + }, + }, + ], + }); + + expect(component).toMatchSnapshot(); + }); + + it('should render a ClayList with items with links', () => { component = new ClayList({ - items: [ + items: sagaItems, + schema: [ { - description: 'Description 1', - href: '#1', - title: 'Item 1', + contentRenderer: 'content', + fieldsMap: { + href: 'downloadHref', + title: 'title', + }, }, + ], + }); + + expect(component).toMatchSnapshot(); + }); + + it('should render a ClayList with items with description', () => { + component = new ClayList({ + items: sagaItems, + schema: [ { - description: 'Description 2', - href: '#2', - title: 'Item 2', + contentRenderer: 'content', + fieldsMap: { + description: 'director', + href: 'downloadHref', + title: 'title', + }, }, + ], + }); + + expect(component).toMatchSnapshot(); + }); + + it('should render a selectable ClayList', () => { + component = new ClayList({ + items: sagaItems, + schema: [ { - description: 'Description 3', - href: '#3', - title: 'Item 3', + contentRenderer: 'content', + fieldsMap: { + description: 'director', + href: 'downloadHref', + title: 'title', + }, }, ], selectable: true, @@ -60,14 +278,220 @@ describe('ClayList', function() { expect(component).toMatchSnapshot(); }); - it('should render a selectable ClayList with header title', () => { + it('should render a selectable ClayList with groups', () => { + component = new ClayList({ + items: groupedItems, + schema: [ + { + contentRenderer: 'content', + fieldsMap: { + description: 'director', + href: 'downloadHref', + title: 'title', + }, + }, + ], + }); + + expect(component).toMatchSnapshot(); + }); + + it('should render a selectable ClayList with icons', () => { component = new ClayList({ - items: [ + items: groupedItems, + schema: [ + { + contentRenderer: 'icon', + fieldName: 'status', + iconsMap: { + 'Watched': 'check-circle', + '*': 'exclamation-circle', + }, + }, + { + contentRenderer: 'content', + fieldsMap: { + description: 'director', + href: 'downloadHref', + title: 'title', + }, + }, + ], + spritemap: spritemap, + }); + + expect(component).toMatchSnapshot(); + }); + + it('should render a selectable ClayList with circle icons', () => { + component = new ClayList({ + items: groupedItems, + schema: [ + { + contentRenderer: 'icon', + fieldName: 'status', + iconsMap: { + 'Watched': 'check-circle', + '*': 'exclamation-circle', + }, + iconShapesMap: { + 'Watched': 'circle', + '*': 'rounded', + }, + }, + { + contentRenderer: 'content', + fieldsMap: { + description: 'director', + href: 'downloadHref', + title: 'title', + }, + }, + ], + spritemap: spritemap, + }); + + expect(component).toMatchSnapshot(); + }); + + it('should render a selectable ClayList with label', () => { + component = new ClayList({ + items: groupedItems, + schema: [ + { + contentRenderer: 'icon', + fieldName: 'status', + iconsMap: { + 'Watched': 'check-circle', + '*': 'exclamation-circle', + }, + iconShapesMap: { + 'Watched': 'circle', + '*': 'rounded', + }, + }, + { + contentRenderer: 'content', + fieldsMap: { + description: 'director', + href: 'downloadHref', + labels: 'status', + title: 'title', + }, + labelStylesMap: { + 'Watched': 'success', + 'Pending': 'warning', + '*': 'danger', + }, + }, + ], + spritemap: spritemap, + }); + + expect(component).toMatchSnapshot(); + }); + + it('should render a selectable ClayList with action menu', () => { + let itemsWithActionItems = []; + + sagaItems.forEach(item => { + let itemWithActionItems = {}; + + for (let key in item) { + if (Object.prototype.hasOwnProperty.call(item, key)) { + itemWithActionItems[key] = item[key]; + } + } + + itemWithActionItems.actionItems = actionItems; + + itemsWithActionItems.push(itemWithActionItems); + }); + + component = new ClayList({ + items: itemsWithActionItems, + schema: [ + { + contentRenderer: 'icon', + fieldName: 'status', + iconsMap: { + 'Watched': 'check-circle', + '*': 'exclamation-circle', + }, + iconShapesMap: { + 'Watched': 'circle', + '*': 'rounded', + }, + }, + { + contentRenderer: 'content', + fieldsMap: { + description: 'director', + href: 'downloadHref', + labels: 'status', + title: 'title', + }, + labelStylesMap: { + 'Watched': 'success', + 'Pending': 'warning', + '*': 'danger', + }, + }, + ], + spritemap: spritemap, + }); + + expect(component).toMatchSnapshot(); + }); + + it('should render a selectable ClayList with quick action menu', () => { + let itemsWithActionItems = []; + + sagaItems.forEach(item => { + let itemWithActionItems = {}; + + for (let key in item) { + if (Object.prototype.hasOwnProperty.call(item, key)) { + itemWithActionItems[key] = item[key]; + } + } + + itemWithActionItems.actionItems = actionItemsWithQuickItems; + + itemsWithActionItems.push(itemWithActionItems); + }); + + component = new ClayList({ + items: itemsWithActionItems, + schema: [ + { + contentRenderer: 'icon', + fieldName: 'status', + iconsMap: { + 'Watched': 'check-circle', + '*': 'exclamation-circle', + }, + iconShapesMap: { + 'Watched': 'circle', + '*': 'rounded', + }, + }, { - title: 'Item 1', + contentRenderer: 'content', + fieldsMap: { + description: 'director', + href: 'downloadHref', + labels: 'status', + title: 'title', + }, + labelStylesMap: { + 'Watched': 'success', + 'Pending': 'warning', + '*': 'danger', + }, }, ], - title: 'Group Header 1', + spritemap: spritemap, }); expect(component).toMatchSnapshot(); @@ -78,9 +502,13 @@ describe('ClayList', function() { component = new ClayList({ events: {itemToggled: spy}, - items: [ + items: groupedItems, + schema: [ { - title: 'Item 1', + contentRenderer: 'simple', + fieldsMap: { + title: 'title', + }, }, ], selectable: true, @@ -91,9 +519,11 @@ describe('ClayList', function() { expect(spy).toHaveBeenCalled(); }); - it('should fail when no items are passed', function() { + it('should fail when no schema is passed', function() { expect(() => { - component = new ClayList(); + component = new ClayList({ + items: [], + }); }).toThrow(); }); }); diff --git a/packages/clay-list/src/__tests__/ClayListItem.js b/packages/clay-list/src/__tests__/ClayListItem.js deleted file mode 100644 index 2b2c7b0c5..000000000 --- a/packages/clay-list/src/__tests__/ClayListItem.js +++ /dev/null @@ -1,236 +0,0 @@ -import ClayListItem from '../ClayListItem'; - -const spritemap = '../node_modules/lexicon-ux/build/images/icons/icons.svg'; - -let component; - -let actionItems = [ - { - href: '#1', - label: 'Option 1', - }, - { - href: '#2', - label: 'Option 2', - separator: true, - }, - { - href: '#3', - label: 'Option 3', - }, -]; - -let actionItemsWithQuickItems = [ - { - href: '#1', - icon: 'trash', - label: 'Option 1', - quickAction: true, - }, - { - href: '#2', - icon: 'download', - label: 'Option 2', - quickAction: true, - separator: true, - }, - { - href: '#3', - icon: 'info-circle-open', - label: 'Option 3', - quickAction: true, - }, -]; - -describe('ClayListItem', function() { - afterEach(() => { - if (component) { - component.dispose(); - } - }); - - it('should render the default markup', () => { - component = new ClayListItem({ - title: 'My Item', - }); - - expect(component).toMatchSnapshot(); - }); - - it('should render a ClayListItem with classes', () => { - component = new ClayListItem({ - elementClasses: 'my-custom-class', - title: 'My Item', - }); - - expect(component).toMatchSnapshot(); - }); - - it('should render a ClayListItem with id', () => { - component = new ClayListItem({ - id: 'myId', - title: 'My Item', - }); - - expect(component).toMatchSnapshot(); - }); - - it('should render a ClayListItem with link', () => { - component = new ClayListItem({ - href: '#1', - title: 'Item 1', - }); - - expect(component).toMatchSnapshot(); - }); - - it('should render a ClayListItem with description', () => { - component = new ClayListItem({ - description: 'Description 1', - title: 'Item 1', - }); - - expect(component).toMatchSnapshot(); - }); - - it('should render a ClayListItem with description and url', () => { - component = new ClayListItem({ - description: 'Description 1', - href: '#1', - title: 'Item 1', - }); - - expect(component).toMatchSnapshot(); - }); - - it('should render a selectable ClayListItem', () => { - component = new ClayListItem({ - description: 'Description 1', - href: '#1', - selectable: true, - title: 'Item 1', - }); - - expect(component).toMatchSnapshot(); - }); - - it('should render a selected ClayListItem', () => { - component = new ClayListItem({ - description: 'Description 1', - href: '#1', - selectable: true, - selected: true, - title: 'Item 1', - }); - - expect(component).toMatchSnapshot(); - }); - - it('should render a ClayListItem with icon', () => { - component = new ClayListItem({ - icon: 'folder', - spritemap: spritemap, - title: 'Item 1', - }); - - expect(component).toMatchSnapshot(); - }); - - it('should render a ClayListItem with circle icons', () => { - component = new ClayListItem({ - icon: 'folder', - iconShape: 'circle', - spritemap: spritemap, - title: 'Item 1', - }); - - expect(component).toMatchSnapshot(); - }); - - it('should render a ClayListItem with one label', () => { - component = new ClayListItem({ - labels: [ - { - label: 'Status', - }, - ], - title: 'Item 1', - }); - - expect(component).toMatchSnapshot(); - }); - - it('should render a ClayListItem with two labels', () => { - component = new ClayListItem({ - labels: [ - { - label: 'Aproved', - }, - { - label: 'Pending', - }, - ], - title: 'Item 1', - }); - - expect(component).toMatchSnapshot(); - }); - - it('should render a ClayListItem with labels with style', () => { - component = new ClayListItem({ - labels: [ - { - label: 'Aproved', - style: 'info', - }, - { - label: 'Pending', - style: 'warning', - }, - ], - title: 'Item 1', - }); - - expect(component).toMatchSnapshot(); - }); - - it('should render a ClayListItem with action menu', () => { - component = new ClayListItem({ - actionItems: actionItems, - spritemap: spritemap, - title: 'Item 1', - }); - - expect(component).toMatchSnapshot(); - }); - - it('should render a ClayListItem with quick action menu', () => { - component = new ClayListItem({ - actionItems: actionItemsWithQuickItems, - spritemap: spritemap, - title: 'Item 1', - }); - - expect(component).toMatchSnapshot(); - }); - - it('should render a ClayListItem and emit an event on item toggled', () => { - const spy = jest.fn(); - - component = new ClayListItem({ - events: {itemToggled: spy}, - selectable: true, - title: 'Item 1', - }); - - component.element.querySelector('input[type="checkbox"]').click(); - - expect(spy).toHaveBeenCalled(); - }); - - it('should fail when no title is passed', function() { - expect(() => { - component = new ClayListItem(); - }).toThrow(); - }); -}); diff --git a/packages/clay-list/src/__tests__/__snapshots__/ClayList.js.snap b/packages/clay-list/src/__tests__/__snapshots__/ClayList.js.snap index 2700d5579..381aa2f1b 100644 --- a/packages/clay-list/src/__tests__/__snapshots__/ClayList.js.snap +++ b/packages/clay-list/src/__tests__/__snapshots__/ClayList.js.snap @@ -4,6 +4,223 @@ exports[`ClayList should render a ClayList with classes 1`] = ``; +exports[`ClayList should render a ClayList with items 1`] = ` + +`; + +exports[`ClayList should render a ClayList with items with description 1`] = ` + +`; + +exports[`ClayList should render a ClayList with items with links 1`] = ` + +`; + +exports[`ClayList should render a ClayList with simple items 1`] = ` + +`; + +exports[`ClayList should render a ClayList with simple items with links 1`] = ` + +`; + exports[`ClayList should render a selectable ClayList 1`] = ` `; -exports[`ClayList should render a selectable ClayList with header title 1`] = ` +exports[`ClayList should render a selectable ClayList with action menu 1`] = ` +`; + +exports[`ClayList should render a selectable ClayList with circle icons 1`] = ` + +`; + +exports[`ClayList should render a selectable ClayList with groups 1`] = ` + +`; + +exports[`ClayList should render a selectable ClayList with icons 1`] = ` + +`; + +exports[`ClayList should render a selectable ClayList with label 1`] = ` + +`; + +exports[`ClayList should render a selectable ClayList with quick action menu 1`] = ` + `; diff --git a/packages/clay-list/src/__tests__/__snapshots__/ClayListItem.js.snap b/packages/clay-list/src/__tests__/__snapshots__/ClayListItem.js.snap deleted file mode 100644 index bef2fc22b..000000000 --- a/packages/clay-list/src/__tests__/__snapshots__/ClayListItem.js.snap +++ /dev/null @@ -1,229 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`ClayListItem should render a ClayListItem with action menu 1`] = ` -
  • -
    -

    Item 1

    -
    -
    -
    - -
    -
  • -`; - -exports[`ClayListItem should render a ClayListItem with circle icons 1`] = ` -
  • -
    - - - - - -
    -
    -

    Item 1

    -
    -
  • -`; - -exports[`ClayListItem should render a ClayListItem with classes 1`] = `
  • My Item
  • `; - -exports[`ClayListItem should render a ClayListItem with description 1`] = ` -
  • -
    -

    Item 1

    -

    Description 1

    -
    -
  • -`; - -exports[`ClayListItem should render a ClayListItem with description and url 1`] = ` -
  • -
    -

    - Item 1 -

    -

    Description 1

    -
    -
  • -`; - -exports[`ClayListItem should render a ClayListItem with icon 1`] = ` -
  • -
    - - - - - -
    -
    -

    Item 1

    -
    -
  • -`; - -exports[`ClayListItem should render a ClayListItem with id 1`] = `
  • My Item
  • `; - -exports[`ClayListItem should render a ClayListItem with labels with style 1`] = ` -
  • -
    -

    Item 1

    -
    - Aproved - Pending -
    -
    -
  • -`; - -exports[`ClayListItem should render a ClayListItem with link 1`] = ` -
  • - Item 1 -
  • -`; - -exports[`ClayListItem should render a ClayListItem with one label 1`] = ` -
  • -
    -

    Item 1

    -
    - Status -
    -
    -
  • -`; - -exports[`ClayListItem should render a ClayListItem with quick action menu 1`] = ` -
  • -
    -

    Item 1

    -
    -
    - - -
    -
  • -`; - -exports[`ClayListItem should render a ClayListItem with two labels 1`] = ` -
  • -
    -

    Item 1

    -
    - Aproved - Pending -
    -
    -
  • -`; - -exports[`ClayListItem should render a selectable ClayListItem 1`] = ` -
  • -
    -
    - -
    -
    -
    -

    - Item 1 -

    -

    Description 1

    -
    -
  • -`; - -exports[`ClayListItem should render a selected ClayListItem 1`] = ` -
  • -
    -
    - -
    -
    -
    -

    - Item 1 -

    -

    Description 1

    -
    -
  • -`; - -exports[`ClayListItem should render the default markup 1`] = `
  • My Item
  • `; diff --git a/packages/clay-table/demos/index.html b/packages/clay-table/demos/index.html index 862c751eb..2e93b03af 100644 --- a/packages/clay-table/demos/index.html +++ b/packages/clay-table/demos/index.html @@ -121,7 +121,7 @@

    director: 'Richard Marquand', downloadHref: '#', rating: 90, - releaseDate: 'May 21th 1980', + releaseDate: 'May 25th 1983', status: 'Watched', title: 'Episode VI: Return of the Jedi', },