Added autocomplete for fields that expect variable names
This commit is contained in:
@@ -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: {
|
||||
|
||||
26
app/imports/ui/components/global/SmartCombobox.vue
Normal file
26
app/imports/ui/components/global/SmartCombobox.vue
Normal 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>
|
||||
@@ -20,7 +20,7 @@ export default {
|
||||
inputValue: this.value,
|
||||
};},
|
||||
props: {
|
||||
value: [String, Number, Date],
|
||||
value: [String, Number, Date, Array],
|
||||
debounceTime: {
|
||||
type: Number,
|
||||
default: 750,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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);
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
Reference in New Issue
Block a user