Skip to content

Commit d15f63b

Browse files
VdustRmarcosmoura
authored andcommitted
feat(MdChips): feedback for duplicated chip (#1281)
* feat(MdChips): feedback for duplicated chip add `md-duplicated` class which has the same style as `md-accent`. add `md-check-duplicated-on-change` props. fix #1212 * fix(MdChips): change api `mdCheckDuplicatedOnChange` to `mdAlwaysCheckDuplicated` * fix(MdChips): change for loop key from `key` to `chip` to prevent triggering animate while removing * docs(MdChips): example and new props for duplicated chip checking fix #1212 * fix(MdChips): always clear `duplicatedChip` on change * style(MdChips): fix style to pass scss-lint * fix(MdChips): rename prop * fix(MdChips): rename prop * fix(MdChips): rename prop * fix(MdChips): rename prop * style(MdChips): adjust code style
1 parent 023723a commit d15f63b

File tree

5 files changed

+123
-11
lines changed

5 files changed

+123
-11
lines changed

docs/app/pages/Components/Chips/Chips.vue

+14
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
<example src="./examples/Static.vue" />
33
<example src="./examples/Editable.vue" />
44
<example src="./examples/ChipCustomTemplate.vue" />
5+
<example src="./examples/DuplicatedFeedback.vue" />
56
<example src="./examples/Themed.vue" />
67

78
<template>
@@ -45,6 +46,13 @@
4546
<code-example title="Scoped Slot" :component="examples['chip-custom-template']" />
4647
</div>
4748

49+
<div class="page-container-section">
50+
<h2>Duplicated Chip</h2>
51+
52+
<p>Chips would reject insertion while a chip was duplicated. You could customize feedback style of the duplicated chip:</p>
53+
<code-example title="Duplicated Feedback" :component="examples['duplicated-feedback']" />
54+
</div>
55+
4856
<div class="page-container-section">
4957
<h2>Hue Colors</h2>
5058

@@ -142,6 +150,12 @@ export default {
142150
type: 'Number',
143151
description: 'Blocks the chips to create items above the limit.',
144152
defaults: 'false'
153+
},
154+
{
155+
name: 'md-check-duplicated',
156+
type: 'Boolean',
157+
description: 'Always check if there is a duplicated chip while changing the input value, or check it only on insertion',
158+
defaults: 'false'
145159
}
146160
]
147161
},
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<template>
2+
<div>
3+
<md-chips class="md-primary" v-model="chips" md-placeholder="Add genre...">
4+
<div class="md-helper-text">Default</div>
5+
</md-chips>
6+
<md-chips class="md-primary shake-on-error" v-model="chips" md-placeholder="Add genre...">
7+
<div class="md-helper-text">Shake duplicated chip on insertion</div>
8+
</md-chips>
9+
<md-chips class="md-primary pulse-on-error" v-model="chips" md-placeholder="Add genre..." md-check-duplicated>
10+
<div class="md-helper-text">Always pulse duplicated chip</div>
11+
</md-chips>
12+
</div>
13+
</template>
14+
15+
<script>
16+
export default {
17+
name: 'DuplicatedFeedback',
18+
data: () => ({
19+
chips: [
20+
'Pop',
21+
'Rock',
22+
'Jazz',
23+
'Metal'
24+
]
25+
})
26+
}
27+
</script>
28+
29+
<style lang="scss" scoped>
30+
.shake-on-error /deep/ .md-duplicated {
31+
animation-name: shake;
32+
animation-duration: 0.5s;
33+
}
34+
35+
@keyframes shake {
36+
0% { transform: translate(15px); }
37+
20% { transform: translate(-15px); }
38+
40% { transform: translate(7px); }
39+
60% { transform: translate(-7px); }
40+
80% { transform: translate(3px); }
41+
100% { transform: translate(0px); }
42+
}
43+
</style>
44+
45+
<style lang="css" scoped>
46+
.pulse-on-error >>> .md-duplicated {
47+
animation-name: pulse;
48+
animation-duration: 0.5s;
49+
animation-iteration-count: infinite;
50+
animation-direction: alternate;
51+
animation-timing-function: ease-in-out
52+
}
53+
54+
@keyframes pulse {
55+
0% { transform: scale(1.1, 1.1); }
56+
100% { transform: scale(0.9, 0.9); }
57+
}
58+
</style>
59+

src/components/MdChips/MdChip.vue

+7-2
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,20 @@
3636
props: {
3737
mdDisabled: Boolean,
3838
mdDeletable: Boolean,
39-
mdClickable: Boolean
39+
mdClickable: Boolean,
40+
mdDuplicated: {
41+
type: Boolean,
42+
default: false
43+
}
4044
},
4145
computed: {
4246
chipClasses () {
4347
return {
4448
'md-disabled': this.mdDisabled,
4549
'md-deletable': this.mdDeletable,
4650
'md-clickable': this.mdClickable,
47-
'md-focused': this.mdHasFocus
51+
'md-focused': this.mdHasFocus,
52+
'md-duplicated': this.mdDuplicated
4853
}
4954
}
5055
}

src/components/MdChips/MdChips.vue

+41-8
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44

55
<md-chip
66
v-for="(chip, key) in value"
7-
:key="key"
7+
:key="chip"
88
:md-deletable="!mdStatic"
99
:md-clickable="!mdStatic"
10+
:md-duplicated="duplicatedChip === chip"
1011
@keydown.enter="$emit('md-click', chip, key)"
1112
@click.native="$emit('md-click', chip, key)"
1213
@md-delete.stop="removeChip(chip)">
@@ -21,6 +22,7 @@
2122
:type="mdInputType"
2223
:id="id"
2324
:placeholder="mdPlaceholder"
25+
@input="handleInput"
2426
@keydown.enter="insertChip"
2527
@keydown.8="handleBackRemove">
2628
</md-input>
@@ -52,10 +54,15 @@
5254
},
5355
mdPlaceholder: [String, Number],
5456
mdStatic: Boolean,
55-
mdLimit: Number
57+
mdLimit: Number,
58+
mdCheckDuplicated: {
59+
type: Boolean,
60+
default: false
61+
}
5662
},
5763
data: () => ({
58-
inputValue: ''
64+
inputValue: '',
65+
duplicatedChip: null
5966
}),
6067
computed: {
6168
chipsClasses () {
@@ -70,13 +77,19 @@
7077
},
7178
methods: {
7279
insertChip ({ target }) {
73-
if (
74-
!this.inputValue ||
75-
this.value.includes(this.inputValue) ||
76-
!this.modelRespectLimit
77-
) {
80+
if (!this.inputValue || !this.modelRespectLimit) {
81+
return
82+
}
83+
84+
if (this.value.includes(this.inputValue)) {
85+
this.duplicatedChip = null
86+
// to trigger animate
87+
this.$nextTick(() => {
88+
this.duplicatedChip = this.inputValue
89+
})
7890
return
7991
}
92+
8093
this.value.push(this.inputValue)
8194
this.$emit('input', this.value)
8295
this.$emit('md-insert', this.inputValue)
@@ -94,6 +107,26 @@
94107
if (!this.inputValue) {
95108
this.removeChip(this.value[this.value.length - 1])
96109
}
110+
},
111+
handleInput () {
112+
if (this.mdCheckDuplicated) {
113+
this.checkDuplicated()
114+
} else {
115+
this.duplicatedChip = null
116+
}
117+
},
118+
checkDuplicated () {
119+
if (!this.value.includes(this.inputValue)) {
120+
this.duplicatedChip = null
121+
return
122+
}
123+
if (!this.mdCheckDuplicated) return
124+
this.duplicatedChip = this.inputValue
125+
}
126+
},
127+
watch: {
128+
value () {
129+
this.checkDuplicated()
97130
}
98131
}
99132
})

src/components/MdChips/theme.scss

+2-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@
6262
}
6363
}
6464

65-
&.md-accent {
65+
&.md-accent,
66+
&.md-duplicated {
6667
@include md-theme-property(background-color, accent);
6768
@include md-theme-property(color, text-primary, accent);
6869

0 commit comments

Comments
 (0)