Added autocomplete for fields that expect variable names

This commit is contained in:
Thaum Rystra
2020-04-29 10:53:06 +02:00
parent 966fcc449d
commit ed9cfee9f9
13 changed files with 128 additions and 35 deletions

View File

@@ -1,9 +1,14 @@
<template lang="html">
<computed :value="value" :scope="scope" v-bind="$attrs"/>
<computed
:value="value"
:scope="scope"
v-bind="$attrs"
/>
</template>
<script>
import Computed from '/imports/ui/components/computation/Computed.vue';
import Creatures from '/imports/api/creature/Creatures.js';
export default {
inject: ['computationContext'],
@@ -13,6 +18,7 @@ export default {
props: {
value: {
type: String,
default: undefined,
},
},
meteor: {

View File

@@ -0,0 +1,26 @@
<template lang="html">
<v-combobox
v-bind="$attrs"
:loading="loading"
:error-messages="errors"
:value="safeValue"
:menu-props="{auto: true, lazy: true}"
box
@change="change"
@focus="focused = true"
@blur="focused = false"
>
<slot
slot="prepend"
name="prepend"
/>
</v-combobox>
</template>
<script>
import SmartInput from '/imports/ui/components/global/SmartInputMixin.js';
export default {
mixins: [SmartInput],
};
</script>

View File

@@ -20,7 +20,7 @@ export default {
inputValue: this.value,
};},
props: {
value: [String, Number, Date],
value: [String, Number, Date, Array],
debounceTime: {
type: Number,
default: 750,

View File

@@ -1,11 +1,13 @@
import Vue from "vue";
import Vue from 'vue';
// Global components
import DatePicker from '/imports/ui/components/global/DatePicker.vue';
import TextField from '/imports/ui/components/global/TextField.vue';
import TextArea from '/imports/ui/components/global/TextArea.vue';
import SmartSelect from '/imports/ui/components/global/SmartSelect.vue';
import SmartCombobox from '/imports/ui/components/global/SmartCombobox.vue';
Vue.component("date-picker", DatePicker);
Vue.component("text-field", TextField);
Vue.component("text-area", TextArea);
Vue.component("smart-select", SmartSelect);
Vue.component('DatePicker', DatePicker);
Vue.component('TextField', TextField);
Vue.component('TextArea', TextArea);
Vue.component('SmartSelect', SmartSelect);
Vue.component('SmartCombobox', SmartCombobox);

View File

@@ -1,10 +1,11 @@
<template lang="html">
<div>
<div class="layout row">
<text-field
<smart-combobox
label="Attribute"
hint="The attribute this adjustment will apply to"
style="flex-basis: 300px;"
:items="attributeList"
:value="model.stat"
:error-messages="errors.stat"
:debounce-time="debounceTime"
@@ -35,7 +36,10 @@
</template>
<script>
import attributeListMixin from '/imports/ui/properties/forms/shared/lists/attributeListMixin.js';
export default {
mixins: [attributeListMixin],
props: {
model: {
type: Object,

View File

@@ -1,9 +1,10 @@
<template lang="html">
<div class="layout row">
<text-field
<smart-combobox
label="Attribute"
hint="The attribute variable name that will be consumed"
style="flex-basis: 300px;"
:items="attributeList"
:value="model.variableName"
:error-messages="errors.variableName"
:debounce-time="debounceTime"
@@ -22,7 +23,10 @@
</template>
<script>
import attributeListMixin from '/imports/ui/properties/forms/shared/lists/attributeListMixin.js';
export default {
mixins: [attributeListMixin],
props: {
model: {
type: Object,

View File

@@ -50,14 +50,15 @@
@change="(value, ack) => $emit('change', {path: ['calculation'], value, ack})"
/>
<text-field
<smart-combobox
label="Stat"
class="mr-2"
:value="model.stats[0]"
:items="stats"
multiple
:value="model.stats"
:items="attributeList"
:error-messages="errors.stats"
:debounce-time="debounceTime"
@change="(value, ack) => $emit('change', {path: ['stats'], value: [value], ack})"
@change="(value, ack) => $emit('change', {path: ['stats'], value, ack})"
/>
</div>
</div>
@@ -65,9 +66,11 @@
<script>
import getEffectIcon from '/imports/ui/utility/getEffectIcon.js';
import attributeListMixin from '/imports/ui/properties/forms/shared/lists/attributeListMixin.js';
const ICON_SPIN_DURATION = 300;
export default {
mixins: [attributeListMixin],
props: {
model: {
type: Object,
@@ -77,10 +80,6 @@
type: Object,
default: () => ({}),
},
stats: {
type: Array,
default: () => [],
},
debounceTime: {
type: Number,
default: undefined,
@@ -142,6 +141,7 @@
},
methods: {
getEffectIcon,
log: console.log,
}
};
</script>

View File

@@ -8,14 +8,15 @@
@change="(value, ack) => $emit('change', {path: ['name'], value, ack})"
/>
<div class="layout row wrap justify-start proficiency-form">
<text-field
<smart-combobox
label="Skill"
class="mr-2"
:value="model.stats[0]"
:items="stats"
multiple
:value="model.stats"
:items="skillList"
:error-messages="errors.stats"
:debounce-time="debounceTime"
@change="(value, ack) => $emit('change', {path: ['stats'], value: [value], ack})"
@change="(value, ack) => $emit('change', {path: ['stats'], value, ack})"
/>
<proficiency-select
label="Proficiency"
@@ -30,11 +31,13 @@
<script>
import ProficiencySelect from '/imports/ui/properties/forms/shared/ProficiencySelect.vue';
import skillListMixin from '/imports/ui/properties/forms/shared/lists/skillListMixin.js';
export default {
components: {
ProficiencySelect,
},
mixins: [skillListMixin],
props: {
model: {
type: Object,

View File

@@ -17,11 +17,12 @@
:debounce-time="debounceTime"
@change="(value, ack) => $emit('change', {path: ['variableName'], value, ack})"
/>
<text-field
<smart-combobox
label="Ability"
:value="model.ability"
style="flex-basis: 300px;"
hint="Which ability is this skill based off of"
:items="abilityScoreList"
:error-messages="errors.ability"
:debounce-time="debounceTime"
@change="(value, ack) => $emit('change', {path: ['ability'], value, ack})"
@@ -73,6 +74,7 @@
<script>
import ProficiencySelect from '/imports/ui/properties/forms/shared/ProficiencySelect.vue';
import FormSection from '/imports/ui/properties/forms/shared/FormSection.vue';
import createListOfProperties from '/imports/ui/properties/forms/shared/lists/createListOfProperties.js';
export default {
components: {
@@ -119,6 +121,14 @@
},
]
};},
meteor: {
abilityScoreList(){
return createListOfProperties({
type: 'attribute',
attributeType: 'ability',
});
},
},
};
</script>

View File

@@ -56,21 +56,16 @@
watch: {
'value': {
immediate: true,
handler(newValue, oldValue){
handler(newValue){
let newIcon = proficiencyIcon(newValue);
if (!oldValue){
// Skip animation
this.iconClass='leaving';
setTimeout(() => {
this.displayedIcon = newIcon;
} else {
this.iconClass='leaving';
setTimeout(() => {
this.displayedIcon = newIcon;
this.iconClass='arriving';
requestAnimationFrame(() => {
this.iconClass='';
});
}, ICON_SPIN_DURATION / 2);
}
this.iconClass='arriving';
requestAnimationFrame(() => {
this.iconClass='';
});
}, ICON_SPIN_DURATION / 2);
},
},
}

View File

@@ -0,0 +1,11 @@
import createListOfProperties from '/imports/ui/properties/forms/shared/lists/createListOfProperties.js';
const attributeListMixin = {
meteor: {
attributeList(){
return createListOfProperties({type: 'attribute'});
},
},
};
export default attributeListMixin;

View File

@@ -0,0 +1,21 @@
import CreatureProperties from '/imports/api/creature/CreatureProperties.js';
import LibraryNodes from '/imports/api/library/LibraryNodes.js';
export default function createListOfProperties(filter = {}){
filter.removed = {$ne: true};
let propertyList = [];
let variableNames = new Set();
function addUniquePropertys(property){
if (property.variableName && !variableNames.has(property.variableName)){
variableNames.add(property.variableName);
propertyList.push({
text: property.name || property.variableName,
value: property.variableName,
propertyType: property.propertyType,
});
}
}
CreatureProperties.find(filter).forEach(addUniquePropertys);
LibraryNodes.find(filter).forEach(addUniquePropertys);
return Array.from(variableNames);
}

View File

@@ -0,0 +1,11 @@
import createListOfProperties from '/imports/ui/properties/forms/shared/lists/createListOfProperties.js'
const skillListMixin = {
meteor: {
skillList(){
return createListOfProperties({type: 'skill'});
},
},
};
export default skillListMixin;