Skip to content

Commit

Permalink
feat: show guide of selected node (#30)
Browse files Browse the repository at this point in the history
* feat: show guide of selected node

* chore: change selected border color

* fix: show selected border in correct place with scaled

* refactor: send real element instead of bounds when node is selected

* fix: deselect when resize to avoid showing inappropriate bounds

* fix: deselect on start dragging
  • Loading branch information
ktsn committed Apr 29, 2018
1 parent 943b070 commit c84f20b
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 18 deletions.
14 changes: 6 additions & 8 deletions src/view/components/Node.vue
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,10 @@ export default Vue.extend({
computed: {
vnodeData(): VNodeData {
const { data: node, scope, selectable, selected } = this
const { data: node, scope, selectable } = this
const data = convertToVNodeData(node.startTag.attributes, scope)
if (selectable) {
if (selected) {
data.class.push('selected')
}
data.attrs!.tabindex = '0'
// The vnode may be a native element or ContainerVueComponent,
// so we should set both `on` and `nativeOn` here.
data.on = data.nativeOn = {
Expand Down Expand Up @@ -95,7 +89,11 @@ export default Vue.extend({
methods: {
onClick(event: Event): void {
event.stopPropagation()
this.$emit('select', this.data)
this.$emit('select', {
ast: this.data,
element: event.currentTarget
})
},
onDragOver(event: DragEvent): void {
Expand Down
23 changes: 19 additions & 4 deletions src/view/components/PageMain.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@
<Renderer
v-if="renderingDocument"
:document="renderingDocument"
:selected-path="selectedPath"
:width="width"
:height="height"
:scale="scale"
@select="select"
@dragover="setDraggingPlace"
@add="applyDraggingElement"
@resize="resize"
@resize="onResize"
@zoom="zoom"
/>
</div>
Expand All @@ -21,7 +22,7 @@
:width="width"
:height="height"
:scale="scale"
@resize="resize"
@resize="onResize"
@zoom="zoom"
/>
</div>
Expand Down Expand Up @@ -53,7 +54,7 @@
<div class="component-catalog">
<ComponentCatalog
:components="catalog"
@dragstart="startDragging"
@dragstart="onStartDragging"
@dragend="endDragging"
/>
</div>
Expand Down Expand Up @@ -131,7 +132,21 @@ export default Vue.extend({
'updateDeclaration'
]),
...viewportHelpers.mapActions(['resize', 'zoom'])
...viewportHelpers.mapActions(['resize', 'zoom']),
onStartDragging(uri: string): void {
// Deselect to avoid showing incorrect bounds
this.select(undefined)
this.startDragging(uri)
},
onResize(size: { width: number; height: number }): void {
// Deselect to avoid showing incorrect bounds
this.select(undefined)
this.resize(size)
}
}
})
</script>
Expand Down
64 changes: 63 additions & 1 deletion src/view/components/Renderer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<div class="renderer" @click="$emit('select')">
<div class="renderer-scroll-content" :style="scrollContentStyle">
<Viewport
ref="viewport"
:width="width"
:height="height"
:scale="scale"
Expand All @@ -15,10 +16,16 @@
:data="document.data"
:child-components="document.childComponents"
:styles="document.styleCode"
@select="$emit('select', arguments[0])"
@select="onSelectNode"
@dragover="$emit('dragover', arguments[0])"
@add="$emit('add')"
/>

<div
v-if="selectedPath.length > 0"
:style="selectedStyle"
class="renderer-selected"
/>
</Viewport>
</div>
</div>
Expand All @@ -29,6 +36,7 @@ import Vue from 'vue'
import Viewport from './Viewport.vue'
import VueComponent from './VueComponent.vue'
import { ScopedDocument } from '../store/modules/project'
import { Element } from '@/parser/template/types'
const scrollContentPadding = 100
Expand All @@ -45,6 +53,10 @@ export default Vue.extend({
type: Object as () => ScopedDocument,
required: true
},
selectedPath: {
type: Array as () => number[],
required: true
},
width: {
type: Number,
required: true
Expand All @@ -66,6 +78,13 @@ export default Vue.extend({
height: 0
},
selectedBounds: {
left: 0,
top: 0,
width: 0,
height: 0
},
/**
* Indicates how much the scroll offset will be changed on after the next render.
* This is needed to retain the viewport position visually even after the scroll content size is changed.
Expand Down Expand Up @@ -123,6 +142,42 @@ export default Vue.extend({
x: size.width / 2,
y: size.height / 2
}
},
selectedStyle(): Record<string, string> {
const { selectedBounds: bounds } = this
return {
left: bounds.left + 'px',
top: bounds.top + 'px',
width: bounds.width + 'px',
height: bounds.height + 'px'
}
}
},
methods: {
onSelectNode({
ast,
element
}: {
ast: Element
element: HTMLElement
}): void {
const viewport = this.$refs.viewport as Vue
const viewportBounds = viewport.$el.getBoundingClientRect()
const bounds = element.getBoundingClientRect()
// The bounds are modified by the current scale.
// To show the selected border with accurate bounds,
// we need to get original bounds by dividing them by the scale.
this.selectedBounds = {
left: (bounds.left - viewportBounds.left) / this.scale,
top: (bounds.top - viewportBounds.top) / this.scale,
width: bounds.width / this.scale,
height: bounds.height / this.scale
}
this.$emit('select', ast)
}
},
Expand Down Expand Up @@ -179,4 +234,11 @@ export default Vue.extend({
.renderer-scroll-content {
position: relative;
}
.renderer-selected {
position: absolute;
box-sizing: border-box;
border: 1px solid #0f2fff;
pointer-events: none;
}
</style>
5 changes: 5 additions & 0 deletions test/view/Renderer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ describe('Renderer', () => {
const wrapper = shallow<any>(Renderer, {
propsData: {
document: {},
selectedPath: [],
width: 800,
height: 600,
scale: 1
Expand All @@ -50,6 +51,7 @@ describe('Renderer', () => {
const wrapper = shallow<any>(Renderer, {
propsData: {
document: {},
selectedPath: [],
width: 800,
height: 1200,
scale: 1
Expand All @@ -65,6 +67,7 @@ describe('Renderer', () => {
const wrapper = shallow<any>(Renderer, {
propsData: {
document: {},
selectedPath: [],
width: 500,
height: 500,
scale: 2
Expand All @@ -80,6 +83,7 @@ describe('Renderer', () => {
const wrapper = shallow<any>(Renderer, {
propsData: {
document: {},
selectedPath: [],
width: 800,
height: 600,
scale: 1
Expand Down Expand Up @@ -109,6 +113,7 @@ describe('Renderer', () => {
const wrapper = shallow<any>(Renderer, {
propsData: {
document: {},
selectedPath: [],
width: 800,
height: 600,
scale: 1
Expand Down
27 changes: 22 additions & 5 deletions test/view/VueComponent/select.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,23 @@ import * as td from 'testdouble'
import { createTemplate, h, a, render } from '../../helpers/template'

describe('VueComponent select event', () => {
beforeAll(() => {
Element.prototype.getBoundingClientRect = jest.fn(() => ({
x: 0,
y: 0,
left: 0,
right: 0,
top: 0,
bottom: 0,
width: 0,
height: 0
}))
})

afterAll(() => {
delete Element.prototype.getBoundingClientRect
})

it('should catch select event from descendant nodes', () => {
const third = h('button', [a('id', 'third')], [])
// prettier-ignore
Expand All @@ -26,10 +43,10 @@ describe('VueComponent select event', () => {
wrapper.find('#second').trigger('click')
wrapper.find('#third').trigger('click')

td.verify(spy(root), { times: 1 })
td.verify(spy(first), { times: 1 })
td.verify(spy(second), { times: 1 })
td.verify(spy(third), { times: 1 })
td.verify(spy(td.matchers.contains({ ast: root })), { times: 1 })
td.verify(spy(td.matchers.contains({ ast: first })), { times: 1 })
td.verify(spy(td.matchers.contains({ ast: second })), { times: 1 })
td.verify(spy(td.matchers.contains({ ast: third })), { times: 1 })
})

it('should catch select event of child component', () => {
Expand Down Expand Up @@ -68,6 +85,6 @@ describe('VueComponent select event', () => {

wrapper.vm.$on('select', spy)
wrapper.find('#child-button').trigger('click')
td.verify(spy(comp), { times: 1 })
td.verify(spy(td.matchers.contains({ ast: comp })), { times: 1 })
})
})

0 comments on commit c84f20b

Please sign in to comment.