How to Change item fill,colors, when using Vue.js


#1

I’m making XD plugin for changing color selected items.

image

I refer to plugin sample that “ui-hello-vue”.

I can showing dialog,but selected items can not change colors.

Consolo show:

not permitted to make changes from the background. Return a Promise to continue execution asynchronously.

I can find information for “object change attribute must asynchronously”,but “return new Promise” in child component resolve error…

what is bad ?

its main.js

//  temporary stubs required for Vue. These will not be required as soon as the XD environment provides setTimeout/clearTimeout
global.setTimeout = function (fn) { fn() }
global.clearTimeout = function () { };


const styles = require("./styles.css");
const Vue = require("vue").default;
const color = require("./color.vue").default;

const { Rectangle,Text, Color } = require("scenegraph");

const chroma = require("chroma-js");
global.chroma = chroma;


function getDialog() {
        document.body.innerHTML = `<dialog><div id="container"></div></dialog>`
        return document.querySelector("dialog");
}
async function colorChanger(selection){
	return new Promise(function(resolve,reject){
			if(selection.items[0]){
				const dialog = getDialog();
				const result = dialog.showModal();

				if(result){
			        var app = new Vue({
			            el: "#container",
			            components: { color },
			            render(h) {
			                return h(color,{
								props: {dialog,selection}
			                })
			            }
			        });
			    }
			}
		resolve();
	});
}
module.exports = {
    commands: {
   		colorChanger
    }
};

its color.vue

<template>
<div class="row">
	<form action="">
	<div class="col" v-for="(elem,i) in color">
		<div>
			<h3>{{ elem.disp }}</h3>
		</div>
		<div>
			<input type="range" min="-180" max="180" step="1" v-model="color[i].num" v-on:change="updateColor" v-if="i == 'h'" />
			<input type="range" min="-50" max="50" step="1" v-model="color[i].num" v-on:change="updateColor" v-else />
		</div>
		<div>{{ elem.num }}</div>
	</div>
	
	<footer class="col col-btn">
		<button v-on:click="reset">reset</button>
		<button v-on:click="close">close</button>
	</footer>
	
	</form>
</div>
</template>

<script>
	const { Rectangle,Text, Color } = require("scenegraph");
    module.exports = {
        props: {
            dialog: {
                type: Object
            },
            selection: {
            	type: Object
            }
        },
        methods: {
        	close(){
        		var vm = this;
        		vm.dialog.close();
        	},
        	reset(){
				this.$set(this.color.h,'num',0);
				this.$set(this.color.s,'num',0);
				this.$set(this.color.l,'num',0);
        	},
        	getColor(rgba){
        		return new Color({
        			r: rgba[1],
        			g: rgba[2],
        			b: rgba[3],
        			a: rgba[4] || 1,
        		});
        	},
        	updateColor(){
        		var vm = this;
	    			vm.selection.items.forEach(function(elem,i){
	    				vm.setColor(elem);
        		});
        	},
        	setColor(elem){
        		var vm = this;
        			if(elem.fill.value){
        				var currentColor = chroma(elem.fill.r,elem.fill.g,elem.fill.b);
						var newColor = currentColor.hsl(currentColor.get('hsl.h') + vm.color.h.num,currentColor.get('hsl.s') + vm.color.s.num,currentColor.get('hsl.l') + vm.color.l.num);
						vm.setColorFunc(elem,newColor,vm);
    				}
        	},
        	setColorFunc(elem,newColor){
        		var vm = this;
        			console.log('fill');
        			elem.fill = vm.getColor(newColor);
        	}
        },
        data() {
            return {
            	color: {
            		h: {
            			num: 0,
            			disp: 'H'
            		},
            		s: {
            			num: 0,
            			disp: 'S'
            		},
            		l: {
            			num: 0,
            			disp: 'B'
            		}
            	}
            }
        }
    }
</script>


<style scoped>
	.row {
		width: 500px;
	}
	.col {
		display: flex;
		align-items: center;
	}
	form > div + div {
		margin-top: 20px;
	}
	.col > div:nth-child(2) {
		flex: 1 1 auto;
	}
	.col > div:nth-child(1),
	.col > div:nth-child(3) {
		text-align: center;
		flex: none;
		width: 50px;
	}
	.col-btn {
		justify-content: flex-end;
	}
	
</style>

thanks.


#2

Read this thread if nothing helps post your problem


#3

Read this may this is the solution


#4

You can’t resolve your promise synchronously as soon as the dialog is shown. You need to return or await the promise that’s returned by showModal() (stored as result in your code) so that your plugin retains “foreground” privileges the whole time the dialog is open.