@signal24/vue-foundation 4.25.3 → 4.25.5

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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@signal24/vue-foundation",
3
3
  "type": "module",
4
- "version": "4.25.3",
4
+ "version": "4.25.5",
5
5
  "description": "Common components, directives, and helpers for Vue 3 apps",
6
6
  "module": "./dist/vue-foundation.es.js",
7
7
  "exports": {
@@ -51,7 +51,9 @@
51
51
 
52
52
  <script lang="ts" setup generic="T, V = T">
53
53
  import { debounce, groupBy, isEqual, uniq } from 'lodash';
54
- import { computed, onMounted, type Ref, ref, watch } from 'vue';
54
+ import { computed, onMounted, ref, watch } from 'vue';
55
+
56
+ import { isNotNullOrUndefined } from '@/helpers';
55
57
 
56
58
  import { escapeHtml } from '../helpers/string';
57
59
  import type { VfSmartSelectOptionDescriptor } from './vf-smart-select.types';
@@ -63,6 +65,7 @@ const VALID_KEYS = `\`1234567890-=[]\\;',./~!@#$%^&*()_+{}|:"<>?qwertyuiopasdfgh
63
65
 
64
66
  const props = defineProps<{
65
67
  modelValue: V | null;
68
+ loadingText?: string;
66
69
  loadOptions?: (searchText: string | null) => Promise<T[]>;
67
70
  options?: T[];
68
71
  prependOptions?: T[];
@@ -82,6 +85,7 @@ const props = defineProps<{
82
85
  formatter?: (option: T) => string;
83
86
  subtitleFormatter?: (option: T) => string;
84
87
  classForOption?: (option: T) => string;
88
+ selectionFormatter?: (option: T) => string;
85
89
  nullTitle?: string;
86
90
  noResultsText?: string;
87
91
  disabled?: boolean;
@@ -108,7 +112,7 @@ const optionsContainer = ref<HTMLDivElement>();
108
112
 
109
113
  const isLoading = ref(false);
110
114
  const isLoaded = ref(false);
111
- const loadedOptions = ref<T[]>([]) as Ref<T[]>;
115
+ const loadedOptions = ref<T[]>();
112
116
  const isSearching = ref(false);
113
117
  const searchText = ref('');
114
118
  const selectedOption = ref<T | null>(null);
@@ -120,7 +124,7 @@ const shouldShowCreateTextOnNewItem = computed(() => props.showCreateTextOnNewIt
120
124
 
121
125
  const effectivePrependOptions = computed(() => props.prependOptions ?? []);
122
126
  const effectiveAppendOptions = computed(() => props.appendOptions ?? []);
123
- const effectiveDisabled = computed(() => !!props.disabled);
127
+ const effectiveDisabled = computed(() => !!props.disabled || (!props.options && !loadedOptions.value));
124
128
  const effectivePlaceholder = computed(() => {
125
129
  if (!isLoaded.value && props.preload) return 'Loading...';
126
130
  if (props.nullTitle) return props.nullTitle;
@@ -149,8 +153,12 @@ const effectiveFormatter = computed(() => {
149
153
  if (props.labelField) return (option: T) => String(option[props.labelField!]);
150
154
  return (option: T) => String(option);
151
155
  });
156
+ const effectiveSelectionFormatter = computed(() => {
157
+ if (props.selectionFormatter) return props.selectionFormatter;
158
+ return effectiveFormatter.value;
159
+ });
152
160
 
153
- const allOptions = computed(() => [...effectivePrependOptions.value, ...loadedOptions.value, ...effectiveAppendOptions.value]);
161
+ const allOptions = computed(() => [...effectivePrependOptions.value, ...(loadedOptions.value ?? []), ...effectiveAppendOptions.value]);
154
162
  const isGrouped = computed(() => !!(props.groupField || props.groupFormatter));
155
163
 
156
164
  const optionsDescriptors = computed(() => {
@@ -249,7 +257,7 @@ watch(() => props.modelValue, handleValueChanged);
249
257
  watch(
250
258
  () => props.options,
251
259
  () => {
252
- loadedOptions.value = props.options ?? [];
260
+ loadedOptions.value = props.options;
253
261
  isLoaded.value = true;
254
262
  }
255
263
  );
@@ -301,17 +309,21 @@ onMounted(async () => {
301
309
  if (props.options) {
302
310
  loadedOptions.value = [...props.options];
303
311
  isLoaded.value = true;
304
- } else if (props.preload) {
312
+ } else if (props.loadOptions && props.preload) {
305
313
  await loadRemoteOptions();
306
314
  }
307
315
 
308
- handleValueChanged();
316
+ if (!props.options && (props.valueField || props.valueExtractor)) {
317
+ searchText.value = props.loadingText ?? '...';
318
+ } else {
319
+ handleValueChanged();
320
+ }
309
321
 
310
322
  watch(selectedOption, () => {
311
323
  if (selectedOption.value !== props.modelValue) {
312
324
  emit(
313
325
  'update:modelValue',
314
- selectedOption.value !== null && effectiveValueExtractor.value !== null
326
+ isNotNullOrUndefined(selectedOption.value) && effectiveValueExtractor.value !== null
315
327
  ? effectiveValueExtractor.value(selectedOption.value)
316
328
  : selectedOption.value
317
329
  );
@@ -536,7 +548,7 @@ function selectOption(option: VfSmartSelectOptionDescriptor<T>) {
536
548
  const selectedDecoratedOption = optionsDescriptors.value.find(decoratedOption => decoratedOption.key == option.key);
537
549
  const realOption = selectedDecoratedOption!.ref;
538
550
  selectedOption.value = realOption!;
539
- selectedOptionTitle.value = effectiveFormatter.value(realOption!);
551
+ selectedOptionTitle.value = effectiveSelectionFormatter.value(realOption!);
540
552
  searchText.value = selectedOptionTitle.value ?? '';
541
553
  }
542
554
 
@@ -549,7 +561,7 @@ function handleValueChanged() {
549
561
  selectedOption.value = effectiveValueExtractor.value
550
562
  ? allOptions.value.find(o => props.modelValue === effectiveValueExtractor.value!(o))
551
563
  : props.modelValue;
552
- selectedOptionTitle.value = selectedOption.value !== null ? effectiveFormatter.value(selectedOption.value) : null;
564
+ selectedOptionTitle.value = isNotNullOrUndefined(selectedOption.value) ? effectiveSelectionFormatter.value(selectedOption.value) : null;
553
565
  searchText.value = selectedOptionTitle.value ?? '';
554
566
  } else {
555
567
  selectedOption.value = null;
@@ -559,7 +571,7 @@ function handleValueChanged() {
559
571
  }
560
572
 
561
573
  function addRemoteOption(option: T) {
562
- loadedOptions.value.unshift(option);
574
+ loadedOptions.value!.unshift(option);
563
575
  }
564
576
 
565
577
  function focusNextInput() {
@@ -18,3 +18,7 @@ export function nullifyEmptyInputs<T extends Record<string, unknown>, K extends
18
18
  }
19
19
  return result;
20
20
  }
21
+
22
+ export function isNotNullOrUndefined<T>(value: T | null | undefined): value is T {
23
+ return value !== null && value !== undefined;
24
+ }