Skip to content
This repository has been archived by the owner on Sep 5, 2024. It is now read-only.

feat(chips): initial commit #2030

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/components/chips/chips-theme.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
md-chips.md-THEME_NAME-theme {
.md-chip {
color: '{{background-contrast}}';
background-color: '{{background-100}}';
}
}
13 changes: 13 additions & 0 deletions src/components/chips/chips.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
(function () {
'use strict';
/**
* @ngdoc module
* @name material.components.chips
*/
/*
* @see js folder for chips implementation
*/
angular.module('material.components.chips', [
'material.core'
]);
})();
51 changes: 51 additions & 0 deletions src/components/chips/chips.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
$chip-font-size: 13px !default;
$chip-height: 22px !default;
$chip-button-padding: 2px !default;
$chip-padding: 0 8px 0 8px !default;
$chip-margin: 0 0 0 8px !default;

.md-chips {
box-shadow: $whiteframe-shadow-z1;
display: block;
font-family: $font-family;
font-size: $chip-font-size;
padding: 8px;
vertical-align: middle;

.md-chip {
border-radius: $chip-height / 2;
box-shadow: $whiteframe-shadow-z1;
display: inline-block;
height: $chip-height;
margin: $chip-margin;
line-height: $chip-height;
padding: $chip-padding;
transform: translate3d(0, 0, 0);

&:first-child {
margin: 0;
}

&.selected {
transform: translate3d(0, -1px, 0);
}

.md-button {
padding: $chip-button-padding;
}
}

.md-chip-worker {
display: inline-block;
line-height: $chip-height + 3px; /* 3px are added to height of chip for...the shadow? */

&:not(:first-child) {
margin: $chip-margin;
}
}

.md-chip-input {
background-color:transparent;
border-width: 0px;
}
}
137 changes: 137 additions & 0 deletions src/components/chips/chips.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
describe('<md-chips>', function() {

beforeEach(module('material.components.chips'));

function compile (str, scope) {
var container;
inject(function ($compile) {
container = $compile(str)(scope);
scope.$apply();
});
return container;
}

function createScope () {
var scope;
var items = ['Apple', 'Banana', 'Orange'];
inject(function ($rootScope) {
scope = $rootScope.$new();
scope.items = items;
});
return scope;
}

function getChipElements(root) {
return angular.element(root[0].querySelectorAll('div.md-chip'));
}

describe('basic functionality', function () {
it('should render a default input element', function() {
var scope = createScope();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a fan of aligning assignment operators, but especially when it's not done consistently

var template = '<md-chips ng-model="items"></md-chips>';
var element = compile(template, scope);
var ctrl = element.controller('mdChips');

element.scope().$apply();
var input = element.find('input');
expect(input.length).toBe(1);
expect(input).toHaveClass('md-chip-input');
});

it('should render a list of chips', function() {
var scope = createScope();
var template = '<md-chips ng-model="items"></md-chips>';
var element = compile(template, scope);
var ctrl = element.controller('mdChips');

element.scope().$apply();
var chips = getChipElements(element);
expect(chips.length).toBe(3);
expect(chips[0].innerHTML).toContain('Apple');
expect(chips[1].innerHTML).toContain('Banana');
expect(chips[2].innerHTML).toContain('Orange');
});

it('should render a user-provided chip template', function() {
var scope = createScope();
var template =
'<md-chips ng-model="items">' +
' <md-chip class="mychiptemplate"></md-chip>' +
'</md-chips>';
var element = compile(template, scope);
var ctrl = element.controller('mdChips');

element.scope().$apply();
var chip = element.find('md-chip');
expect(chip).toHaveClass('mychiptemplate');
});

it('should add a chip', function() {
var scope = createScope();
var template = '<md-chips ng-model="items"></md-chips>';
var element = compile(template, scope);
var ctrl = element.controller('mdChips');

element.scope().$apply();
ctrl.chipBuffer = 'Grape';
element.scope().$apply();

ctrl.appendChipBuffer();
element.scope().$apply();

var chips = getChipElements(element);
expect(chips.length).toBe(4);
expect(chips[0].innerHTML).toContain('Apple');
expect(chips[1].innerHTML).toContain('Banana');
expect(chips[2].innerHTML).toContain('Orange');
expect(chips[3].innerHTML).toContain('Grape');
});

it('should remove a chip', function() {
var scope = createScope();
var template = '<md-chips ng-model="items"></md-chips>';
var element = compile(template, scope);
var ctrl = element.controller('mdChips');

element.scope().$apply();

// Remove "Banana"
ctrl.removeChip(1);
element.scope().$apply();

var chips = getChipElements(element);
expect(chips.length).toBe(2);
expect(chips[0].innerHTML).toContain('Apple');
expect(chips[1].innerHTML).toContain('Orange');
});
});

describe('<md-chip-remove>', function() {
it('should remove a chip', function() {
var scope = createScope();
var template = '<md-chips ng-model="items"></md-chips>';
var element = compile(template, scope);
var ctrl = element.controller('mdChips');
element.scope().$apply();

var chips = getChipElements(element);
expect(chips.length).toBe(3);
// Remove 'Banana'
var db = angular.element(chips[1]).find('md-button');
db[0].click();
element.scope().$apply();

chips = getChipElements(element);
expect(chips.length).toBe(2);

// Remove 'Orange'
db = angular.element(chips[1]).find('md-button');
db[0].click();
element.scope().$apply();

chips = getChipElements(element);
expect(chips.length).toBe(1);
});
});

});
45 changes: 45 additions & 0 deletions src/components/chips/demoBasicUsage/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<div ng-app="inputBasicDemo" ng-controller="DemoCtrl as ctrl" layout="column">

<md-content class="md-padding" layout="column">
<p>
Display a readonly list of strings as chips, using a custom chip template.
</p>

<md-chips ng-model="ctrl.roFruitNames"
readonly="true">
<md-chip><strong>{{$chip}}</strong></md-chip>
</md-chips>

<p>
Use the default chip template.
</p>

<md-chips
ng-model="ctrl.fruitNames"
readonly="ctrl.readonly"></md-chips>

<p>
Use Placeholders.
</p>

<md-chips
ng-model="ctrl.newFruitNames"
readonly="ctrl.readonly"
placeholder="Enter a fruit"
secondary-placeholder="+Fruit"></md-chips>

<p>
Display a list of objects as chips.
</p>

<md-chips ng-model="ctrl.vegObjs"
readonly="ctrl.readonly"
md-chip-append="ctrl.newVeg($chip)">
<md-chip><span>{{$chip.name}}:{{$chip.type}}</span></md-chip>
</md-chips>

<br/>
<md-checkbox ng-model="ctrl.readonly">Readonly</md-checkbox>

</md-content>
</div>
37 changes: 37 additions & 0 deletions src/components/chips/demoBasicUsage/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
(function () {
angular
.module('contactchipsDemo', ['ngMaterial'])
.controller('DemoCtrl', DemoCtrl);

function DemoCtrl ($timeout, $q) {
var self = this;

self.readonly = false;

// Lists of fruit names and Vegetable objects
self.fruitNames = ['Apple', 'Banana', 'Orange'];
self.roFruitNames = angular.copy(self.fruitNames);
self.newFruitNames = [];
self.vegObjs = [
{
'name' : 'Broccoli',
'type' : 'cruciferous'
},
{
'name' : 'Cabbage',
'type' : 'cruciferous'
},
{
'name' : 'Carrot',
'type' : 'root'
}
];

self.newVeg = function(chip) {
return {
name: chip,
type: 'unknown'
};
};
}
})();
42 changes: 42 additions & 0 deletions src/components/chips/js/chipRemoveDirective.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
(function () {
'use strict';
angular
.module('material.components.chips')
.directive('mdChipRemove', MdChipRemove);

/**
* @ngdoc directive
* @name mdChipRemove
* @module material.components.chips
*
* @description
* `<element md-chip-remove>`
* Identifies an element within an <md-chip> as the delete button. This
* directive binds to that element's click event and removes the chip.
*
* @usage
* <hljs lang="html">
* <md-chip>{{$chip}}<button md-chip-remove>x</button></md-chip>
* </hljs>
*/

function MdChipRemove () {
return {
restrict: 'A',
require: ['^mdChips'],
link: function postLink(scope, element, attrs, controllers) {
var mdChipsCtrl = controllers[0];
element.on('click', removeItemListener(mdChipsCtrl, scope));
},
scope: false
};

function removeItemListener(chipsCtrl, scope) {
return function() {
scope.$apply(function() {
chipsCtrl.removeChip(scope.$index);
});
};
}
}
})();
Loading