Skip to content

Commit

Permalink
feat: allow to modify props and data in preview pane (#32)
Browse files Browse the repository at this point in the history
* chore: add a json input component

* chore: retain modified scope of document

* chore: show document scope for rendering component

* chore: provide default value as scope to component catalog

* feat: enable to update props / data value in preview
  • Loading branch information
ktsn committed May 21, 2018
1 parent 1380f22 commit d4442d2
Show file tree
Hide file tree
Showing 11 changed files with 523 additions and 49 deletions.
27 changes: 24 additions & 3 deletions src/view/components/ComponentCatalogPreview.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
:uri="component.uri"
:template="component.template"
:styles="component.styleCode"
:props="component.props"
:data="component.data"
:scope="scope"
:child-components="component.childComponents"
/>
</div>
Expand All @@ -16,7 +15,7 @@
<script lang="ts">
import Vue from 'vue'
import VueComponent from './VueComponent.vue'
import { ScopedDocument } from '../store/modules/project'
import { ScopedDocument, DocumentScope } from '../store/modules/project'
export default Vue.extend({
name: 'ComponentCatalogPreview',
Expand All @@ -30,6 +29,28 @@ export default Vue.extend({
type: Object as () => ScopedDocument,
required: true
}
},
computed: {
scope(): DocumentScope {
const scope: DocumentScope = { props: {}, data: {} }
this.component.props.forEach(prop => {
scope.props[prop.name] = {
type: prop.type,
value: prop.default
}
})
this.component.data.forEach(d => {
scope.data[d.name] = {
type: null,
value: d.default
}
})
return scope
}
}
})
</script>
Expand Down
17 changes: 14 additions & 3 deletions src/view/components/ContainerVueComponent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
v-if="document"
:uri="uri"
:template="document.template"
:props="document.props"
:data="document.data"
:scope="scope"
:child-components="document.childComponents"
:styles="document.styleCode"
:props-data="propsData"
Expand All @@ -14,7 +13,11 @@
<script lang="ts">
import Vue from 'vue'
import VueComponent from './VueComponent.vue'
import { ScopedDocument, projectHelpers } from '../store/modules/project'
import {
ScopedDocument,
projectHelpers,
DocumentScope
} from '../store/modules/project'
export default Vue.extend({
name: 'ContainerVueComponent',
Expand All @@ -36,12 +39,20 @@ export default Vue.extend({
},
computed: {
...projectHelpers.mapState({
scopes: 'documentScopes'
}),
...projectHelpers.mapGetters({
documents: 'scopedDocuments'
}),
document(): ScopedDocument | undefined {
return this.documents[this.uri]
},
scope(): DocumentScope | undefined {
return this.scopes[this.uri]
}
}
})
Expand Down
54 changes: 54 additions & 0 deletions src/view/components/InputJson.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<template>
<input class="input-json" type="text" :value="jsonValue" @change="onChange">
</template>

<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
name: 'InputJson',
props: {
value: [Number, String, Boolean, Object, Array]
},
computed: {
jsonValue(): string {
try {
return this.value === undefined
? 'undefined'
: JSON.stringify(this.value)
} catch (e) {
return 'undefined'
}
}
},
methods: {
onChange(event: Event) {
const input = event.target as HTMLInputElement
const jsonValue = input.value
try {
const value =
jsonValue === 'undefined' ? undefined : JSON.parse(jsonValue)
this.$emit('change', value)
} catch (e) {
input.value = this.jsonValue
this.$emit('error', jsonValue)
}
}
}
})
</script>

<style lang="scss" scoped>
.input-json {
padding: 0;
border-width: 0;
background: none;
font-size: inherit;
font-family: inherit;
}
</style>
10 changes: 9 additions & 1 deletion src/view/components/PageMain.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<Renderer
v-if="renderingDocument"
:document="renderingDocument"
:scope="scope"
:selected-path="selectedPath"
:width="width"
:height="height"
Expand Down Expand Up @@ -48,7 +49,11 @@
</div>

<div class="information-pane-item">
<ScopeInformation :props="document.props" :data="document.data">
<ScopeInformation
:scope="scope"
@update-prop="updatePropValue"
@update-data="updateDataValue"
>
<p class="not-found" slot="not-found-prop">Not found</p>
<p class="not-found" slot="not-found-data">Not found</p>
</ScopeInformation>
Expand Down Expand Up @@ -112,6 +117,7 @@ export default Vue.extend({
...projectHelpers.mapGetters({
document: 'currentDocument',
scope: 'currentScope',
renderingDocument: 'currentRenderingDocument',
scopedDocuments: 'scopedDocuments'
}),
Expand All @@ -135,6 +141,8 @@ export default Vue.extend({
'updateDeclaration'
]),
...projectHelpers.mapMutations(['updatePropValue', 'updateDataValue']),
...viewportHelpers.mapActions(['resize', 'zoom']),
onStartDragging(uri: string): void {
Expand Down
9 changes: 6 additions & 3 deletions src/view/components/Renderer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
<VueComponent
:uri="document.uri"
:template="document.template"
:props="document.props"
:data="document.data"
:scope="scope"
:child-components="document.childComponents"
:styles="document.styleCode"
@select="onSelectNode"
Expand All @@ -35,7 +34,7 @@
import Vue from 'vue'
import Viewport from './Viewport.vue'
import VueComponent from './VueComponent.vue'
import { ScopedDocument } from '../store/modules/project'
import { ScopedDocument, DocumentScope } from '../store/modules/project'
import { Element } from '@/parser/template/types'
const scrollContentPadding = 100
Expand All @@ -53,6 +52,10 @@ export default Vue.extend({
type: Object as () => ScopedDocument,
required: true
},
scope: {
type: Object as () => DocumentScope,
required: true
},
selectedPath: {
type: Array as () => number[],
required: true
Expand Down
70 changes: 48 additions & 22 deletions src/view/components/ScopeInformation.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
<div class="information">
<section class="information-group">
<h2 class="information-title">Props</h2>
<ul v-if="props.length > 0" class="information-list">
<li v-for="prop in props" :key="prop.name" class="information-list-item">
<strong class="information-label">{{ prop.name }}</strong>
<ul v-if="hasProps" class="information-list">
<li v-for="(prop, name) in scope.props" :key="name" class="information-list-item">
<strong class="information-label">{{ name }}</strong>
<span class="information-text">
<span v-if="prop.default === undefined" class="information-placeholder">
{{ prop.type }}
</span>
<span v-else>{{ prop.default }}</span>
<InputJson
:value="prop.value"
@change="updateProp(name, arguments[0])"
/>
</span>
</li>
</ul>
Expand All @@ -20,11 +20,14 @@

<section class="information-group">
<h2 class="information-title">Data</h2>
<ul v-if="data.length > 0" class="information-list">
<li v-for="d in data" :key="d.name" class="information-list-item">
<strong class="information-label">{{ d.name }}</strong>
<ul v-if="hasData" class="information-list">
<li v-for="(d, name) in scope.data" :key="name" class="information-list-item">
<strong class="information-label">{{ name }}</strong>
<span class="information-text">
{{ d.default }}
<InputJson
:value="d.value"
@change="updateData(name, arguments[0])"
/>
</span>
</li>
</ul>
Expand All @@ -37,19 +40,46 @@

<script lang="ts">
import Vue from 'vue'
import { Prop, Data } from '@/parser/script/types'
import InputJson from './InputJson.vue'
import { DocumentScope } from '@/view/store/modules/project'
export default Vue.extend({
name: 'Information',
name: 'ScopeInformation',
components: {
InputJson
},
props: {
props: {
type: Array as { (): Prop[] },
scope: {
type: Object as () => DocumentScope,
required: true
}
},
computed: {
hasProps(): boolean {
return Object.keys(this.scope.props).length > 0
},
data: {
type: Array as { (): Data[] },
required: true
hasData(): boolean {
return Object.keys(this.scope.data).length > 0
}
},
methods: {
updateProp(name: string, value: any): void {
this.$emit('update-prop', {
name,
value
})
},
updateData(name: string, value: any): void {
this.$emit('update-data', {
name,
value
})
}
}
})
Expand Down Expand Up @@ -93,10 +123,6 @@ export default Vue.extend({
content: ':';
}
.information-placeholder {
color: #888;
}
.information-text {
margin-left: 0.5em;
}
Expand Down
33 changes: 18 additions & 15 deletions src/view/components/VueComponent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
import Vue, { VNode } from 'vue'
import Child from './Child.vue'
import { Template } from '@/parser/template/types'
import { Prop, Data, ChildComponent } from '@/parser/script/types'
import { ChildComponent } from '@/parser/script/types'
import { DocumentScope } from '@/view/store/modules/project'
import { resolveControlDirectives, ResolvedChild } from '../rendering'
export default Vue.extend({
Expand All @@ -18,12 +19,8 @@ export default Vue.extend({
type: String,
required: true
},
props: {
type: Array as { (): Prop[] },
required: true
},
data: {
type: Array as { (): Data[] },
scope: {
type: Object as { (): DocumentScope },
required: true
},
childComponents: {
Expand All @@ -37,18 +34,21 @@ export default Vue.extend({
},
computed: {
scope(): Record<string, any> {
const scope: Record<string, any> = {}
scopeValues(): Record<string, any> {
const values: Record<string, any> = {}
this.props.forEach(({ name, default: value }) => {
scope[name] = name in this.propsData ? this.propsData[name] : value
Object.keys(this.scope.props).forEach(name => {
values[name] =
name in this.propsData
? this.propsData[name]
: this.scope.props[name].value
})
this.data.forEach(({ name, default: value }) => {
scope[name] = value
Object.keys(this.scope.data).forEach(name => {
values[name] = this.scope.data[name].value
})
return scope
return values
}
},
Expand All @@ -58,7 +58,10 @@ export default Vue.extend({
if (this.template) {
this.template.children
.reduce<ResolvedChild[]>((acc, child) => {
return resolveControlDirectives(acc, { el: child, scope: this.scope })
return resolveControlDirectives(acc, {
el: child,
scope: this.scopeValues
})
}, [])
.forEach(child => {
return children.push(
Expand Down

0 comments on commit d4442d2

Please sign in to comment.