Skip to content

Commit

Permalink
feat: insert a new declaration to arbitrary position (#73)
Browse files Browse the repository at this point in the history
  • Loading branch information
ktsn committed Nov 25, 2018
1 parent f00a62d commit 27bf37d
Show file tree
Hide file tree
Showing 3 changed files with 181 additions and 62 deletions.
59 changes: 44 additions & 15 deletions src/view/components/StyleInformation.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,23 @@
class="rule"
@click="onClickRule(rule, ruleIndex)"
>
<p class="selector-list">
<p
class="selector-list"
@click.stop="onClickSelectorList(rule, ruleIndex)"
>
<span
v-for="s in rule.selectors"
:key="s"
class="selector"
>{{ s }}</span>
</p>

<ul
class="declaration-list"
@click.stop
>
<ul class="declaration-list">
<li
v-for="(decl, declIndex) in rule.children"
:key="decl.path.join('.')"
class="declaration"
@click.stop="onClickDeclaration(decl, ruleIndex, declIndex)"
>
<StyleDeclaration
:prop="decl.prop"
Expand All @@ -44,7 +45,7 @@
<script lang="ts">
import Vue from 'vue'
import StyleDeclaration from './StyleDeclaration.vue'
import { STRuleForPrint } from '@/parser/style/types'
import { STRuleForPrint, STDeclarationForPrint } from '@/parser/style/types'
export default Vue.extend({
name: 'StyleInformation',
Expand Down Expand Up @@ -89,23 +90,51 @@ export default Vue.extend({
})
},
addDeclaration(
rulePath: number[],
ruleIndex: number,
declIndex: number
): void {
this.$emit('add-declaration', {
path: rulePath.concat(declIndex)
})
// Focus on the new declaration prop after it is added
const unwatch = this.$watch('rules', () => {
this.autoFocusTarget = {
rule: ruleIndex,
declaration: declIndex,
type: 'prop'
}
unwatch()
})
},
removeDeclaration(path: number[]): void {
this.$emit('remove-declaration', { path })
},
onClickRule(rule: STRuleForPrint, index: number): void {
if (this.endingInput) return
this.$emit('add-declaration', {
path: rule.path.concat(rule.children.length)
})
this.addDeclaration(rule.path, index, rule.children.length)
},
// Focus on the new declaration prop
this.autoFocusTarget = {
rule: index,
declaration: rule.children.length,
type: 'prop'
}
onClickSelectorList(rule: STRuleForPrint, index: number): void {
if (this.endingInput) return
this.addDeclaration(rule.path, index, 0)
},
onClickDeclaration(
decl: STDeclarationForPrint,
ruleIndex: number,
declIndex: number
): void {
if (this.endingInput) return
const rulePath = decl.path.slice(0, -1)
this.addDeclaration(rulePath, ruleIndex, declIndex + 1)
},
/*
Expand Down
166 changes: 119 additions & 47 deletions tests/view/StyleInformation.spec.ts
Original file line number Diff line number Diff line change
@@ -1,61 +1,61 @@
import { shallowMount, Wrapper } from '@vue/test-utils'
import StyleInformation from '@/view/components/StyleInformation.vue'
import { STRuleForPrint } from '@/parser/style/types'
import { STRuleForPrint, STDeclarationForPrint } from '@/parser/style/types'

describe('StyleInformation', () => {
describe('moving focus', () => {
const StyleDeclaration = {
name: 'StyleDeclaration',
props: ['prop', 'value', 'autoFocus'],
render(this: any, h: Function) {
return h('div', {
attrs: {
styleDeclarationStub: true,
prop: this.prop,
value: this.value,
autoFocus: this.autoFocus
}
})
}
const StyleDeclaration = {
name: 'StyleDeclaration',
props: ['prop', 'value', 'autoFocus'],
render(this: any, h: Function) {
return h('div', {
attrs: {
styleDeclarationStub: true,
prop: this.prop,
value: this.value,
autoFocus: this.autoFocus
}
})
}
}

const rules: STRuleForPrint[] = [
{
path: [0],
selectors: ['a'],
children: [
{
path: [0, 0],
prop: 'color',
value: 'red'
},
{
path: [0, 1],
prop: 'font-size',
value: '22px'
}
]
}
]

const create = () => {
return shallowMount(StyleInformation, {
propsData: {
rules
const rules: STRuleForPrint[] = [
{
path: [0],
selectors: ['a'],
children: [
{
path: [0, 0],
prop: 'color',
value: 'red'
},
stubs: {
StyleDeclaration
{
path: [0, 1],
prop: 'font-size',
value: '22px'
}
})
]
}
]

const toDeclarationHtml = (wrapper: Wrapper<any>) => {
return wrapper
.findAll(StyleDeclaration)
.wrappers.map(w => w.html())
.join('\n')
}
const create = () => {
return shallowMount(StyleInformation, {
propsData: {
rules
},
stubs: {
StyleDeclaration
}
})
}

const toDeclarationHtml = (wrapper: Wrapper<any>) => {
return wrapper
.findAll('[styledeclarationstub]')
.wrappers.map(w => w.html())
.join('\n')
}

describe('moving focus', () => {
it('does not move focus if editing is ended by blur', () => {
const wrapper = create()
wrapper
Expand Down Expand Up @@ -116,4 +116,76 @@ describe('StyleInformation', () => {
expect(toDeclarationHtml(wrapper)).toMatchSnapshot()
})
})

describe('add a new declaration', () => {
const newDecl = {
path: [0, 99],
prop: 'font-weight',
value: 'bold'
}

const addTo = (decl: STDeclarationForPrint, index: number) => {
return [
{
...rules[0],
children: [
...rules[0].children.slice(0, index),
decl,
...rules[0].children.slice(index)
]
}
]
}

it('adds to the first position', async () => {
const wrapper = create()
wrapper.find('.selector-list').trigger('click')

expect(wrapper.emitted('add-declaration')[0][0]).toEqual({
path: [0, 0]
})

wrapper.setProps({
rules: addTo(newDecl, 0)
})

await wrapper.vm.$nextTick()

expect(toDeclarationHtml(wrapper)).toMatchSnapshot()
})

it('adds to the last position', async () => {
const wrapper = create()
wrapper.find('.rule').trigger('click')

expect(wrapper.emitted('add-declaration')[0][0]).toEqual({
path: [0, 2]
})

wrapper.setProps({
rules: addTo(newDecl, 2)
})

await wrapper.vm.$nextTick()

expect(toDeclarationHtml(wrapper)).toMatchSnapshot()
})

it('inserts to the clicked position', async () => {
const wrapper = create()
wrapper.find('.declaration').trigger('click')

expect(wrapper.emitted('add-declaration')[0][0]).toEqual({
path: [0, 1]
})

wrapper.setProps({
rules: addTo(newDecl, 1)
})

await wrapper.vm.$nextTick()

expect(toDeclarationHtml(wrapper)).toMatchSnapshot()
})
})
})
18 changes: 18 additions & 0 deletions tests/view/__snapshots__/StyleInformation.spec.ts.snap
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`StyleInformation add a new declaration adds to the first position 1`] = `
<div styledeclarationstub="true" prop="font-weight" value="bold" autofocus="prop"></div>
<div styledeclarationstub="true" prop="color" value="red"></div>
<div styledeclarationstub="true" prop="font-size" value="22px"></div>
`;

exports[`StyleInformation add a new declaration adds to the last position 1`] = `
<div styledeclarationstub="true" prop="color" value="red"></div>
<div styledeclarationstub="true" prop="font-size" value="22px"></div>
<div styledeclarationstub="true" prop="font-weight" value="bold" autofocus="prop"></div>
`;

exports[`StyleInformation add a new declaration inserts to the clicked position 1`] = `
<div styledeclarationstub="true" prop="color" value="red"></div>
<div styledeclarationstub="true" prop="font-weight" value="bold" autofocus="prop"></div>
<div styledeclarationstub="true" prop="font-size" value="22px"></div>
`;

exports[`StyleInformation moving focus adds a new declaration and moves focus to it 1`] = `
<div styledeclarationstub="true" prop="color" value="red"></div>
<div styledeclarationstub="true" prop="font-size" value="22px"></div>
Expand Down

0 comments on commit 27bf37d

Please sign in to comment.