@signal24/vue-foundation 3.3.3 → 3.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/.eslintrc.js +16 -0
  2. package/.prettierrc.json +7 -0
  3. package/CHANGES.md +6 -3
  4. package/package.json +26 -13
  5. package/postcss.config.js +1 -1
  6. package/src/app.js +2 -2
  7. package/src/components/ajax-select.vue +10 -6
  8. package/src/components/alert.vue +25 -27
  9. package/src/components/index.js +6 -11
  10. package/src/components/modal.vue +18 -10
  11. package/src/components/smart-select.vue +104 -59
  12. package/src/config.js +1 -1
  13. package/src/directives/autofocus.js +4 -3
  14. package/src/directives/confirm-button.js +2 -2
  15. package/src/directives/date-input.js +7 -9
  16. package/src/directives/datetime.js +11 -9
  17. package/src/directives/disabled.js +4 -5
  18. package/src/directives/duration.js +7 -8
  19. package/src/directives/index.js +1 -1
  20. package/src/directives/infinite-scroll.js +1 -1
  21. package/src/directives/readonly.js +5 -6
  22. package/src/directives/tooltip.js +58 -61
  23. package/src/directives/user-text.js +1 -1
  24. package/src/filters/index.js +9 -6
  25. package/src/helpers/array.js +13 -14
  26. package/src/helpers/context-menu.js +16 -18
  27. package/src/helpers/delay.js +1 -1
  28. package/src/helpers/error.js +6 -9
  29. package/src/helpers/http.js +27 -25
  30. package/src/helpers/index.js +1 -1
  31. package/src/helpers/mask.js +27 -20
  32. package/src/helpers/number.js +2 -2
  33. package/src/helpers/string.js +17 -17
  34. package/src/helpers/vue.js +2 -2
  35. package/src/index.js +5 -5
  36. package/src/plugins/index.js +6 -6
  37. package/src/plugins/infinite-scroll/hook.js +2 -2
  38. package/src/plugins/infinite-scroll.js +20 -10
  39. package/src/plugins/resize-watcher.js +2 -4
package/.eslintrc.js ADDED
@@ -0,0 +1,16 @@
1
+ module.exports = {
2
+ root: true,
3
+ env: {
4
+ node: true
5
+ },
6
+ extends: ['plugin:vue/vue3-essential', 'eslint:recommended', '@vue/prettier'],
7
+ rules: {
8
+ 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
9
+ 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
10
+ 'simple-import-sort/imports': 'error',
11
+ 'simple-import-sort/exports': 'error',
12
+ 'prettier/prettier': 'warn',
13
+ 'no-unused-vars': 'warn'
14
+ },
15
+ plugins: ['simple-import-sort']
16
+ };
@@ -0,0 +1,7 @@
1
+ {
2
+ "arrowParens": "avoid",
3
+ "printWidth": 120,
4
+ "singleQuote": true,
5
+ "tabWidth": 4,
6
+ "trailingComma": "none"
7
+ }
package/CHANGES.md CHANGED
@@ -1,10 +1,13 @@
1
1
  # Release notes
2
+
2
3
  All notable changes to this project will be documented in this file.
3
4
  This project adheres to [Semantic Versioning](http://semver.org/).
4
5
 
5
6
  ## 1.0.1
6
- - Update dependencies
7
- - Fix $confirmDestroy
7
+
8
+ - Update dependencies
9
+ - Fix $confirmDestroy
8
10
 
9
11
  ## 1.0.0
10
- - Initial public release
12
+
13
+ - Initial public release
package/package.json CHANGED
@@ -1,15 +1,28 @@
1
1
  {
2
- "name": "@signal24/vue-foundation",
3
- "version": "3.3.3",
4
- "description": "Common components, directives, and helpers for Vue 3 apps",
5
- "main": "src/index.js",
6
- "license": "MIT",
7
- "dependencies": {
8
- "axios": "^0.21.1",
9
- "jquery": "^3.6.0",
10
- "lodash": "^4.17.21",
11
- "moment": "^2.29.1",
12
- "vue": "^3.1.2",
13
- "vue-stash-nested": "fergusean/vue-stash-nested#vue-foundation-3"
14
- }
2
+ "name": "@signal24/vue-foundation",
3
+ "version": "3.7.0",
4
+ "description": "Common components, directives, and helpers for Vue 3 apps",
5
+ "main": "src/index.js",
6
+ "scripts": {
7
+ "format": "prettier --write . && eslint src --fix"
8
+ },
9
+ "license": "MIT",
10
+ "dependencies": {
11
+ "axios": "^0.26.0",
12
+ "jquery": "^3.6.0",
13
+ "lodash": "^4.17.21",
14
+ "moment": "^2.29.1",
15
+ "vue-stash-nested": "fergusean/vue-stash-nested#vue-foundation-3"
16
+ },
17
+ "devDependencies": {
18
+ "@vue/eslint-config-prettier": "^7.0.0",
19
+ "eslint": "^8.10.0",
20
+ "eslint-plugin-prettier": "^4.0.0",
21
+ "eslint-plugin-simple-import-sort": "^7.0.0",
22
+ "eslint-plugin-vue": "^8.5.0",
23
+ "prettier": "^2.5.1",
24
+ "sass": "^1.49.9",
25
+ "sass-loader": "^12",
26
+ "vue": "^3.2.31"
27
+ }
15
28
  }
package/postcss.config.js CHANGED
@@ -2,4 +2,4 @@ module.exports = {
2
2
  plugins: {
3
3
  autoprefixer: {}
4
4
  }
5
- }
5
+ };
package/src/app.js CHANGED
@@ -1,4 +1,4 @@
1
- import { createApp, h } from 'vue'
1
+ import { createApp, h } from 'vue';
2
2
 
3
3
  let rootComponent;
4
4
  function setRootComponent(inComponent) {
@@ -17,7 +17,7 @@ const app = createApp({
17
17
  },
18
18
 
19
19
  render() {
20
- return h(rootComponent)
20
+ return h(rootComponent);
21
21
  }
22
22
  });
23
23
 
@@ -1,8 +1,12 @@
1
1
  <template>
2
- <select v-if="!options" disabled><option>{{ loadingText || 'Loading...' }}</option></select>
2
+ <select v-if="!options" disabled>
3
+ <option>{{ loadingText || 'Loading...' }}</option>
4
+ </select>
3
5
  <select v-else v-model="selectedItem">
4
6
  <option v-if="nullText" :value="null">{{ nullText }}</option>
5
- <option v-for="option in options" :key="option.id" :value="option">{{ textKey ? option[textKey] : option }}</option>
7
+ <option v-for="option in options" :key="option.id" :value="option">
8
+ {{ textKey ? option[textKey] : option }}
9
+ </option>
6
10
  </select>
7
11
  </template>
8
12
 
@@ -14,7 +18,7 @@ export default {
14
18
  return {
15
19
  options: null,
16
20
  selectedItem: null
17
- }
21
+ };
18
22
  },
19
23
 
20
24
  watch: {
@@ -38,7 +42,7 @@ export default {
38
42
  methods: {
39
43
  async load() {
40
44
  this.options = null;
41
- let params = this.params ? { params: this.params } : undefined
45
+ let params = this.params ? { params: this.params } : undefined;
42
46
  let result = await this.$http.get(this.url, params);
43
47
  let options = this.itemsKey ? result.data[this.itemsKey] : result.data;
44
48
  this.preprocessor && this.preprocessor(options);
@@ -46,5 +50,5 @@ export default {
46
50
  this.selectedItem = this.modelValue;
47
51
  }
48
52
  }
49
- }
50
- </script>
53
+ };
54
+ </script>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <modal class="vf-alert" :class="classes">
2
+ <Modal class="vf-alert" :class="classes">
3
3
  <template v-if="!this.isBare" v-slot:header>
4
4
  <h1>{{ title }}</h1>
5
5
  </template>
@@ -14,13 +14,18 @@
14
14
  </template>
15
15
  <button v-else class="default" @click="ok" v-autofocus>OK</button>
16
16
  </template>
17
- </modal>
17
+ </Modal>
18
18
  </template>
19
19
 
20
20
  <script>
21
21
  import app from '../app';
22
+ import Modal from './modal';
22
23
 
23
24
  const classDef = {
25
+ components: {
26
+ Modal
27
+ },
28
+
24
29
  data() {
25
30
  return {
26
31
  isBare: false,
@@ -29,17 +34,15 @@ const classDef = {
29
34
  title: null,
30
35
  message: null,
31
36
  shouldConfirm: false
32
- }
37
+ };
33
38
  },
34
39
 
35
40
  created() {
36
- if (typeof(this.message) == 'object') {
41
+ if (typeof this.message == 'object') {
37
42
  if (this.message.html) {
38
43
  this.isHtml = true;
39
44
  this.message = this.message.html;
40
- }
41
-
42
- else if (this.message instanceof Error) {
45
+ } else if (this.message instanceof Error) {
43
46
  let err = this.message;
44
47
  err.handle();
45
48
 
@@ -60,51 +63,46 @@ export default classDef;
60
63
  async function launchModal(context, classDef, ...args) {
61
64
  classDef = { ...classDef, __modalId: Math.random().toString(36).substring(2, 10) };
62
65
  return await context.$modal.apply(context, [classDef, ...args]);
63
- };
66
+ }
64
67
 
65
- app.config.globalProperties.$alert = async function(title, message) {
68
+ app.config.globalProperties.$alert = async function (title, message) {
66
69
  return await launchModal(this, classDef, { title, message });
67
- }
70
+ };
68
71
 
69
- app.config.globalProperties.$confirm = async function(title, message, options) {
72
+ app.config.globalProperties.$confirm = async function (title, message, options) {
70
73
  options = options || {};
71
74
  const result = await launchModal(this, classDef, { title, message, shouldConfirm: true, ...options });
72
75
  return !!result;
73
- }
76
+ };
74
77
 
75
- app.config.globalProperties.$confirmDestroy = function(title, message, options) {
78
+ app.config.globalProperties.$confirmDestroy = function (title, message, options) {
76
79
  options = options || {};
77
80
  options.classes = options.classes || [];
78
81
  options.classes.push('destructive');
79
82
  return this.$confirm(title, message, options);
80
- }
83
+ };
81
84
 
82
- app.config.globalProperties.$wait = function(title, message) {
85
+ app.config.globalProperties.$wait = function (title, message) {
83
86
  if (title && !message) {
84
87
  message = title;
85
88
  title = undefined;
86
- }
87
- else if (!title && !message) {
89
+ } else if (!title && !message) {
88
90
  message = 'Please wait...';
89
91
  }
90
92
 
91
93
  let resolved = null;
92
94
  let promise = new Promise((resolve, reject) => {
93
95
  launchModal(this, classDef, { title, message, isBare: true, classes: ['wait'] }, resolve);
94
- })
95
- .then(inResolved => resolved = inResolved);
96
+ }).then(inResolved => (resolved = inResolved));
96
97
 
97
98
  this.$endWait = async () => {
98
99
  delete this.$endWait;
99
- if (resolved)
100
- await resolved.$dismiss();
101
- else
102
- await promise.then(() => resolved.$dismiss());
103
- }
100
+ if (resolved) await resolved.$dismiss();
101
+ else await promise.then(() => resolved.$dismiss());
102
+ };
104
103
 
105
104
  return this.$endWait;
106
- }
107
-
105
+ };
108
106
  </script>
109
107
 
110
108
  <style lang="scss">
@@ -129,4 +127,4 @@ app.config.globalProperties.$wait = function(title, message) {
129
127
  }
130
128
  }
131
129
  }
132
- </style>
130
+ </style>
@@ -1,17 +1,12 @@
1
1
  import app from '../app';
2
-
3
- import AjaxSelect from './ajax-select'
2
+ import AjaxSelect from './ajax-select';
4
3
  app.component('AjaxSelect', AjaxSelect);
5
4
 
6
- // do not register Alert with Vue or our customizations to
7
- // on-the-fly alerts won't take effect, as Vue will use
8
- // the already-cached 'Alert' component instead of recompiling
9
- // TODO: ^ is this for mutating Alert during dev, or...?
10
- import Alert from './alert'
11
- Alert;
5
+ import Alert from './alert';
6
+ app.component('Alert', Alert);
12
7
 
13
- import Modal from './modal'
8
+ import Modal from './modal';
14
9
  app.component('Modal', Modal);
15
10
 
16
- import SmartSelect from './smart-select'
17
- app.component('SmartSelect', SmartSelect);
11
+ import SmartSelect from './smart-select';
12
+ app.component('SmartSelect', SmartSelect);
@@ -1,6 +1,11 @@
1
1
  <template>
2
2
  <div class="vf-overlay vf-modal-wrap">
3
- <form action="." class="vf-modal" :class="{ scrolls: $isPropTruthy(this.scrolls) }" @submit.prevent="$emit('formSubmit')">
3
+ <form
4
+ action="."
5
+ class="vf-modal"
6
+ :class="{ scrolls: $isPropTruthy(this.scrolls) }"
7
+ @submit.prevent="$emit('formSubmit')"
8
+ >
4
9
  <div v-if="$slots.header" class="vf-modal-header">
5
10
  <slot name="header" />
6
11
  <i v-if="$isPropTruthy(this.closeX)" class="close" @click="$parent.$dismiss()"></i>
@@ -26,8 +31,7 @@ export default {
26
31
 
27
32
  if (this.$isPropTruthy(this.closeOnMaskClick)) {
28
33
  this.$el.addEventListener('click', e => {
29
- if (e.target == this.$el)
30
- this.$parent.$dismiss();
34
+ if (e.target == this.$el) this.$parent.$dismiss();
31
35
  });
32
36
  }
33
37
  },
@@ -49,7 +53,7 @@ export default {
49
53
  }
50
54
  }
51
55
  }
52
- }
56
+ };
53
57
 
54
58
  import app from '../app';
55
59
  import { markRaw } from 'vue';
@@ -66,14 +70,18 @@ function bootModal(modalId) {
66
70
  this.$options.storeParent = this.$modalOpener;
67
71
 
68
72
  let originalDataFn = this.$options.data;
69
- this.$options.data = function() {
73
+ this.$options.data = function () {
70
74
  const injectedData = config.injectedData || {};
71
75
  const keepOriginalKeys = this.$options.keepOriginal || [];
72
76
  let data = originalDataFn ? originalDataFn.apply(this) : {};
73
77
 
74
78
  for (let key in injectedData) {
75
79
  if (!keepOriginalKeys.includes(key)) {
76
- if (injectedData[key] !== null && typeof(injectedData[key]) == 'object' && injectedData[key].constructor === Object) {
80
+ if (
81
+ injectedData[key] !== null &&
82
+ typeof injectedData[key] == 'object' &&
83
+ injectedData[key].constructor === Object
84
+ ) {
77
85
  data[key] = cloneDeep(injectedData[key]);
78
86
  } else {
79
87
  data[key] = injectedData[key];
@@ -116,7 +124,7 @@ app.mixin({
116
124
  }
117
125
  });
118
126
 
119
- app.config.globalProperties.$modal = function(classDef, injectedData, instanceCreationCallback) {
127
+ app.config.globalProperties.$modal = function (classDef, injectedData, instanceCreationCallback) {
120
128
  return new Promise((resolve, reject) => {
121
129
  const modalId = classDef.__modalId || classDef.__file || Math.random().toString(36).substring(2, 10);
122
130
  classDef.__modalId = modalId;
@@ -132,7 +140,7 @@ app.config.globalProperties.$modal = function(classDef, injectedData, instanceCr
132
140
  app.vm.store.rootInjections.push(markRaw(classDef));
133
141
  });
134
142
  });
135
- }
143
+ };
136
144
 
137
145
  // TODO: see about a injecting a root modal container & HMR inside it
138
146
  // modals, on render, can hot move themselves to body end
@@ -163,7 +171,7 @@ app.config.globalProperties.$modal = function(classDef, injectedData, instanceCr
163
171
 
164
172
  .vf-modal {
165
173
  background: white;
166
- box-shadow: 0px 3px 6px 0px rgba(0,0,0,.15);
174
+ box-shadow: 0px 3px 6px 0px rgba(0, 0, 0, 0.15);
167
175
  min-width: 200px;
168
176
  max-width: 95%;
169
177
  max-height: 95%;
@@ -187,4 +195,4 @@ app.config.globalProperties.$modal = function(classDef, injectedData, instanceCr
187
195
  flex-shrink: 1;
188
196
  flex-basis: 0%;
189
197
  }
190
- </style>
198
+ </style>
@@ -41,14 +41,16 @@ import debounce from 'lodash/debounce';
41
41
  const nullSymbol = Symbol(null);
42
42
  const createSymbol = Symbol('create');
43
43
 
44
- const VALID_KEYS = `\`1234567890-=[]\;',./~!@#$%^&*()_+{}|:"<>?qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM`;
44
+ const VALID_KEYS = `\`1234567890-=[]\\;',./~!@#$%^&*()_+{}|:"<>?qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM`;
45
45
 
46
46
  export default {
47
- emits: ['optionsLoaded', 'createItem'],
47
+ emits: ['optionsLoaded', 'createItem', 'update:modelValue'],
48
48
 
49
49
  props: [
50
50
  'modelValue',
51
51
  'options',
52
+ 'prependOptions',
53
+ 'appendOptions',
52
54
  'preload',
53
55
  'url',
54
56
  'urlParams',
@@ -71,8 +73,7 @@ export default {
71
73
  data() {
72
74
  return {
73
75
  isLoaded: false,
74
- resolvedOptions: [],
75
- decoratedOptions: [],
76
+ loadedOptions: [],
76
77
  isSearching: false,
77
78
  searchText: '',
78
79
  selectedOption: null,
@@ -84,8 +85,11 @@ export default {
84
85
  },
85
86
 
86
87
  computed: {
88
+ /**
89
+ * EFFECTIVE PROPS
90
+ */
87
91
  effectiveDisabled() {
88
- return this.disabled || !this.resolvedOptions;
92
+ return this.disabled || !this.loadedOptions;
89
93
  },
90
94
 
91
95
  effectivePlaceholder() {
@@ -94,8 +98,73 @@ export default {
94
98
  return this.placeholder || '';
95
99
  },
96
100
 
101
+ effectiveIdKey() {
102
+ return this.idKey || 'id';
103
+ },
104
+
105
+ effectiveTitleKey() {
106
+ return this.titleKey || 'name';
107
+ },
108
+
109
+ effectiveValueKey() {
110
+ if (this.valueKey) return this.valueKey;
111
+ if (this.options && !Array.isArray(this.options)) return this.effectiveIdKey;
112
+ return undefined;
113
+ },
114
+
115
+ effectiveNoResultsText() {
116
+ return this.noResultsText || 'No options match your search.';
117
+ },
118
+
119
+ /**
120
+ * OPTIONS GENERATION
121
+ */
122
+
123
+ loadedOptionsArray() {
124
+ return this.arrayifyOptions(this.loadedOptions);
125
+ },
126
+
127
+ prependOptionsArray() {
128
+ return this.prependOptions ? this.arrayifyOptions(this.prependOptions) : [];
129
+ },
130
+
131
+ appendOptionsArray() {
132
+ return this.appendOptions ? this.arrayifyOptions(this.appendOptions) : [];
133
+ },
134
+
135
+ fullOptionsArray() {
136
+ return [...this.prependOptionsArray, ...this.loadedOptionsArray, ...this.appendOptionsArray];
137
+ },
138
+
139
+ optionsDescriptors() {
140
+ return this.fullOptionsArray.map((option, index) => {
141
+ const title = this.getOptionTitle(option);
142
+ const subtitle = this.getOptionSubtitle(option);
143
+ const strippedTitle = title ? title.text.trim().toLowerCase() : '';
144
+ const strippedSubtitle = subtitle ? subtitle.text.trim().toLowerCase() : '';
145
+
146
+ let searchContent = [];
147
+ if (this.searchFields) {
148
+ this.searchFields.forEach(field => {
149
+ option[field] && searchContent.push(String(option[field]).toLowerCase());
150
+ });
151
+ } else {
152
+ searchContent.push(strippedTitle);
153
+ strippedSubtitle && searchContent.push(strippedSubtitle);
154
+ }
155
+
156
+ return {
157
+ key: typeof option == 'object' ? option[this.effectiveIdKey] || index : option,
158
+ titleHtml: title.html,
159
+ subtitleHtml: subtitle?.html,
160
+ searchContent: searchContent.join(''),
161
+ ref: option
162
+ };
163
+ });
164
+ },
165
+
97
166
  effectiveOptions() {
98
- let options = [...this.decoratedOptions];
167
+ let options = [...this.optionsDescriptors];
99
168
 
100
169
  if (this.isSearching) {
101
170
  const strippedSearchText = this.searchText.trim().toLowerCase();
@@ -115,7 +184,8 @@ export default {
115
184
  });
116
185
 
117
186
  if (this.shouldShowCreateOption) {
118
- const hasExactMatch = options.find(option => option.searchContent === strippedSearchText) !== undefined;
187
+ const hasExactMatch =
188
+ options.find(option => option.searchContent === strippedSearchText) !== undefined;
119
189
  if (!hasExactMatch) {
120
190
  options.push({
121
191
  key: createSymbol,
@@ -124,9 +194,7 @@ export default {
124
194
  }
125
195
  }
126
196
  }
127
- }
128
-
129
- else if (this.nullTitle) {
197
+ } else if (this.nullTitle) {
130
198
  options.unshift({
131
199
  key: nullSymbol,
132
200
  titleHtml: this.nullTitle
@@ -134,18 +202,6 @@ export default {
134
202
  }
135
203
 
136
204
  return options;
137
- },
138
-
139
- effectiveIdKey() {
140
- return this.idKey || 'id';
141
- },
142
-
143
- effectiveTitleKey() {
144
- return this.titleKey || 'name';
145
- },
146
-
147
- effectiveNoResultsText() {
148
- return this.noResultsText || 'No options match your search.';
149
205
  }
150
206
  },
151
207
 
@@ -157,7 +213,7 @@ export default {
157
213
  },
158
214
 
159
215
  options() {
160
- this.resolvedOptions = this.options;
216
+ this.loadedOptions = this.options;
161
217
  },
162
218
 
163
219
  url() {
@@ -170,32 +226,7 @@ export default {
170
226
 
171
227
  // data
172
228
 
173
- resolvedOptions() {
174
- this.decoratedOptions = this.resolvedOptions.map((option, index) => {
175
- const title = this.getOptionTitle(option);
176
- const subtitle = this.getOptionSubtitle(option);
177
- const strippedTitle = title ? title.text.trim().toLowerCase() : '';
178
- const strippedSubtitle = subtitle ? subtitle.text.trim().toLowerCase() : '';
179
-
180
- let searchContent = [];
181
- if (this.searchFields) {
182
- this.searchFields.forEach(field => {
183
- option[field] && searchContent.push(String(option[field]).toLowerCase());
184
- });
185
- } else {
186
- searchContent.push(strippedTitle);
187
- strippedSubtitle && searchContent.push(strippedSubtitle);
188
- }
189
-
190
- return {
191
- key: typeof option == 'object' ? option[this.effectiveIdKey] || index : option,
192
- titleHtml: title.html,
193
- subtitleHtml: subtitle?.html,
194
- searchContent: searchContent.join(''),
195
- ref: option
196
- };
197
- });
198
-
229
+ optionsDescriptors() {
199
230
  this.shouldDisplayOptions && setTimeout(this.highlightInitialOption, 0);
200
231
  },
201
232
 
@@ -226,7 +257,7 @@ export default {
226
257
  this.shouldShowCreateOption = this.$attrs['onCreateItem'] !== undefined;
227
258
 
228
259
  if (this.options) {
229
- this.resolvedOptions = this.options;
260
+ this.loadedOptions = this.options;
230
261
  this.isLoaded = true;
231
262
  } else if (this.$isPropTruthy(this.preload)) {
232
263
  this.performInitialLoad();
@@ -235,7 +266,10 @@ export default {
235
266
  this.handleValueChanged();
236
267
 
237
268
  this.$watch('selectedOption', () => {
238
- const newValue = this.selectedOption && this.valueKey ? this.selectedOption[this.valueKey] : this.selectedOption;
269
+ const newValue =
270
+ this.selectedOption && this.effectiveValueKey
271
+ ? this.selectedOption[this.effectiveValueKey]
272
+ : this.selectedOption;
239
273
  newValue === this.modelValue || this.$emit('update:modelValue', newValue);
240
274
  });
241
275
  },
@@ -243,7 +277,7 @@ export default {
243
277
  methods: {
244
278
  async performInitialLoad() {
245
279
  await this.reloadOptions();
246
- this.$emit('optionsLoaded', this.resolvedOptions);
280
+ this.$emit('optionsLoaded', this.loadedOptions);
247
281
 
248
282
  if (this.$isPropTruthy(this.remoteSearch)) {
249
283
  this.$watch('searchText', debounce(this.reloadOptionsIfSearching, 250));
@@ -254,7 +288,7 @@ export default {
254
288
  if (this.preload) return this.reloadOptions();
255
289
  if (!this.isLoaded) return;
256
290
  this.isLoaded = false;
257
- this.resolvedOptions = [];
291
+ this.loadedOptions = [];
258
292
  },
259
293
 
260
294
  async reloadOptions() {
@@ -263,7 +297,7 @@ export default {
263
297
  this.$isPropTruthy(this.remoteSearch) && this.searchText && (params.q = this.searchText);
264
298
 
265
299
  const result = await this.$http.get(this.url, { params: params });
266
- this.resolvedOptions = result.data;
300
+ this.loadedOptions = result.data;
267
301
  this.isLoaded = true;
268
302
  },
269
303
 
@@ -429,10 +463,10 @@ export default {
429
463
  this.selectedOptionTitle = null;
430
464
  this.$emit('createItem', createText);
431
465
  } else {
432
- const optionIndex = this.decoratedOptions.findIndex(
466
+ const selectedDecoratedOption = this.optionsDescriptors.find(
433
467
  decoratedOption => decoratedOption.key == option.key
434
468
  );
435
- const realOption = this.resolvedOptions[optionIndex];
469
+ const realOption = selectedDecoratedOption.ref;
436
470
  this.selectedOption = realOption;
437
471
  this.selectedOptionTitle = this.getOptionTitle(this.selectedOption).text;
438
472
  this.searchText = this.selectedOptionTitle || '';
@@ -443,8 +477,10 @@ export default {
443
477
 
444
478
  handleValueChanged() {
445
479
  if (this.modelValue) {
446
- if (this.valueKey) {
447
- this.selectedOption = this.resolvedOptions.find(option => option[this.valueKey] === this.modelValue);
480
+ if (this.effectiveValueKey) {
481
+ this.selectedOption = this.fullOptionsArray.find(
482
+ option => option[this.effectiveValueKey] === this.modelValue
483
+ );
448
484
  } else {
449
485
  this.selectedOption = this.modelValue;
450
486
  }
@@ -507,7 +543,16 @@ export default {
507
543
  },
508
544
 
509
545
  addRemoteOption(option) {
510
- this.resolvedOptions.push(option);
546
+ this.loadedOptions.push(option);
547
+ },
548
+
549
+ arrayifyOptions(options) {
550
+ return Array.isArray(options)
551
+ ? options
552
+ : Object.entries(options).map(entry => ({
553
+ [this.effectiveIdKey]: entry[0],
554
+ [this.effectiveTitleKey]: entry[1]
555
+ }));
511
556
  }
512
557
  }
513
558
  };
package/src/config.js CHANGED
@@ -8,4 +8,4 @@ function applyConfiguration(inOptions) {
8
8
 
9
9
  Object.defineProperty(options, 'set', { value: applyConfiguration, enumerable: false });
10
10
 
11
- export default options;
11
+ export default options;