Skip to content

Commit

Permalink
feat: group
Browse files Browse the repository at this point in the history
Ref #103
  • Loading branch information
Ernest committed Mar 30, 2021
1 parent c619b4a commit 7fe7a37
Show file tree
Hide file tree
Showing 11 changed files with 475 additions and 16 deletions.
5 changes: 5 additions & 0 deletions cypress/fixtures/example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
}
51 changes: 51 additions & 0 deletions cypress/integration/props/disabled/group/disabled-by-group.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<link
type="text/css"
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css"
/>
<link type="text/css" rel="stylesheet" href="/dist/index.css" />
<script src="https://unpkg.com/vue@next/dist/vue.global.prod.js"></script>
</head>

<body>
<div id="app"></div>
<script src="/dist/vue-next-select.iife.js"></script>
<script>
const { ref, watch, createApp } = Vue

const app = createApp({
name: 'app',
setup() {
const selectedOptions = ref([])
const options = ref([
{ label: 'Partial', value: ['i', 'love'], group: true, disabled: true },
{ label: 'I', value: 'i' },
{ label: 'Love', value: 'love' },
{ label: 'Vue', value: 'vue' },
])
return {
selectedOptions,
options,
}
},
template: `
<vue-select
v-model="selectedOptions"
:options="options"
multiple
label-by="label"
value-by="value"
group-by="group"
></vue-select>
`,
})

app.component('vue-select', VueNextSelect)
app.mount(document.querySelector('#app'))
</script>
</body>
</html>
51 changes: 51 additions & 0 deletions cypress/integration/props/disabled/group/disabled-by-values.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<link
type="text/css"
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css"
/>
<link type="text/css" rel="stylesheet" href="/dist/index.css" />
<script src="https://unpkg.com/vue@next/dist/vue.global.prod.js"></script>
</head>

<body>
<div id="app"></div>
<script src="/dist/vue-next-select.iife.js"></script>
<script>
const { ref, watch, createApp } = Vue

const app = createApp({
name: 'app',
setup() {
const selectedOptions = ref([])
const options = ref([
{ label: 'All', value: ['i', 'love', 'vue'], group: true },
{ label: 'I', value: 'i', disabled: true },
{ label: 'Love', value: 'love', disabled: true },
{ label: 'Vue', value: 'vue', disabled: true },
])
return {
selectedOptions,
options,
}
},
template: `
<vue-select
v-model="selectedOptions"
:options="options"
multiple
label-by="label"
value-by="value"
group-by="group"
></vue-select>
`,
})

app.component('vue-select', VueNextSelect)
app.mount(document.querySelector('#app'))
</script>
</body>
</html>
19 changes: 19 additions & 0 deletions cypress/integration/props/disabled/group/index.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/// <reference types="cypress" />
import path from 'path'

context('disabled group', () => {
it('all of values should be disabled if group is disabled', () => {
cy.visit(path.join(__dirname, 'disabled-by-group.html'))
cy.get('.vue-select').click()

cy.get('.vue-dropdown-item.disabled').should('have.length', 3)
cy.get('.vue-dropdown-item').last().should('not.have.class', 'disabled')
})

it("should be disabled if all of group's value are disabled", () => {
cy.visit(path.join(__dirname, 'disabled-by-values.html'))
cy.get('.vue-select').click()

cy.get('.vue-dropdown-item.group.disabled').should('have.length', 1)
})
})
51 changes: 51 additions & 0 deletions cypress/integration/props/options/group/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<link
type="text/css"
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css"
/>
<link type="text/css" rel="stylesheet" href="/dist/index.css" />
<script src="https://unpkg.com/vue@next/dist/vue.global.prod.js"></script>
</head>

<body>
<div id="app"></div>
<script src="/dist/vue-next-select.iife.js"></script>
<script>
const { ref, watch, createApp } = Vue

const app = createApp({
name: 'app',
setup() {
const selectedOptions = ref([])
const options = ref([
{ label: 'All', value: ['i', 'love', 'vue'], group: true },
{ label: 'I', value: 'i' },
{ label: 'Love', value: 'love' },
{ label: 'Vue', value: 'vue' },
])
return {
selectedOptions,
options,
}
},
template: `
<vue-select
v-model="selectedOptions"
:options="options"
multiple
label-by="label"
value-by="value"
group-by="group"
></vue-select>
`,
})

app.component('vue-select', VueNextSelect)
app.mount(document.querySelector('#app'))
</script>
</body>
</html>
37 changes: 37 additions & 0 deletions cypress/integration/props/options/group/index.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/// <reference types="cypress" />
import path from 'path'

context('group-options', () => {
it('should select values of group option when click an group option', () => {
cy.visit(path.join(__dirname, 'index.html'))
cy.get('.vue-select').click()

cy.get('.vue-dropdown-item.group').trigger('click')

cy.get('.vue-dropdown-item.selected').should('have.length', 4)
})

it('should deselect values of group option when all of its values are selected', () => {
cy.visit(path.join(__dirname, 'index.html'))
cy.get('.vue-select').click()
cy.get('.vue-dropdown-item.group').trigger('click')

cy.get('.vue-dropdown-item.group').trigger('click')

cy.get('.vue-dropdown-item.selected').should('have.length', 0)
})

it('group should be select if and only if all of its values are selected', () => {
cy.visit(path.join(__dirname, 'index.html'))
cy.get('.vue-select').click()

cy.get('.vue-dropdown-item:not(.group)').first().trigger('click').should('have.class', 'selected')
cy.get('.vue-dropdown-item.group').should('not.have.class', 'selected')

cy.get('.vue-dropdown-item:not(.group)').first().next().trigger('click').should('have.class', 'selected')
cy.get('.vue-dropdown-item.group').should('not.have.class', 'selected')

cy.get('.vue-dropdown-item:not(.group)').first().next().next().trigger('click').should('have.class', 'selected')
cy.get('.vue-dropdown-item.group').should('have.class', 'selected')
})
})
150 changes: 150 additions & 0 deletions docs/group.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
{
const jsCode = `
import { ref, createApp } from 'vue'
import VueSelect from 'vue-next-select'
// for composition API
export default createApp({
name: 'app',
components: {
VueSelect
},
setup() {
const model = ref(['express', 'koa'])
const searchInput = ref('')
const hanldeSearchInput = event => {
searchInput.value = event.target.value
}
const visibleOptions = computed(() => {
if (searchInput.value === '') return options
return options.filter(option => option.group || option.label.indexOf(searchInput.value) >= 0)
})
return {
model,
options,
visibleOptions,
hanldeSearchInput,
}
},
})
// for option API
export default createApp({
name: 'app',
components: {
VueSelect
},
data() {
return {
model: ['express', 'koa'],
options: [
{ label: 'All', value: ['express', 'koa', 'django', 'flask'], group: true, level: 0 },
{ label: 'NodeJS', value: ['express', 'koa'], group: true, level: 1 },
{ label: 'Express', value: 'express', level: 2 },
{ label: 'Koa', value: 'koa', level: 2 },
{ label: 'Python', value: ['django', 'flask'], group: true, level: 1 },
{ label: 'Django', value: 'django', level: 2 },
{ label: 'Flask', value: 'flask', level: 2 },
],
searchInput: '',
}
},
computed: {
visibleOptions () {
if (this.searchInput === '') return this.options
return this.options.filter(option => option.group || option.label.indexOf(this.searchInput) >= 0)
},
},
methods: {
hanldeSearchInput (event) {
this.searchInput = event.target.value
},
},
})
`.trim()

const htmlCode = `
<vue-select
v-model="model"
:options="options"
multiple
label-by="label"
value-by="value"
group-by="group"
placeholder="Pick some"
:visible-options="visibleOptions"
searchable
@search:input="hanldeSearchInput"
>
<template #dropdown-item="{ option }">
<div :style="'padding-left: ' + option.level * 8 + 'px;'">{{ option.label }}</div>
</template>
</vue-select>
`.trim()

const { ref, computed, createApp } = Vue

const app = createApp({
name: 'app',
setup() {
const model = ref(['express', 'koa'])

const options = [
{ label: 'All', value: ['express', 'koa', 'django', 'flask'], group: true, level: 0 },
{ label: 'NodeJS', value: ['express', 'koa'], group: true, level: 1 },
{ label: 'Express', value: 'express', level: 2 },
{ label: 'Koa', value: 'koa', level: 2 },
{ label: 'Python', value: ['django', 'flask'], group: true, level: 1 },
{ label: 'Django', value: 'django', level: 2 },
{ label: 'Flask', value: 'flask', level: 2 },
]

const searchInput = ref('')
const hanldeSearchInput = event => {
searchInput.value = event.target.value
}
const visibleOptions = computed(() => {
if (searchInput.value === '') return options
return options.filter(option => option.group || option.label.indexOf(searchInput.value) >= 0)
})

return {
model,
options,
visibleOptions,
hanldeSearchInput,

jsCode,
htmlCode,
}
},
template: `
<vue-select
v-model="model"
:options="options"
multiple
label-by="label"
value-by="value"
group-by="group"
placeholder="Pick some"
:visible-options="visibleOptions"
searchable
@search:input="hanldeSearchInput"
>
<template #dropdown-item="{ option }">
<div :style="'padding-left: ' + option.level * 8 + 'px;'">{{ option.label }}</div>
</template>
</vue-select>
<pre class="result"><code class="plaintext">{{ model }}</code></pre>
<p><i>Code sample:</i></p>
<pre><code class="html">{{ htmlCode }}</code></pre>
<pre><code class="javascript">{{ jsCode }}</code></pre>
`,
})

app.component('vue-select', VueNextSelect)
app.mount(document.querySelector('#group'))
}
Loading

0 comments on commit 7fe7a37

Please sign in to comment.