quasar-ui-danx 0.4.1 → 0.4.3
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/dist/danx.es.js +7234 -6741
- package/dist/danx.es.js.map +1 -1
- package/dist/danx.umd.js +11 -5
- package/dist/danx.umd.js.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +3 -1
- package/src/components/ActionTable/ActionTable.vue +31 -43
- package/src/components/ActionTable/Columns/ActionTableColumn.vue +19 -18
- package/src/components/ActionTable/Filters/CollapsableFiltersSidebar.vue +15 -14
- package/src/components/ActionTable/Filters/{FilterFieldList.vue → FilterList.vue} +26 -26
- package/src/components/ActionTable/Filters/FilterableField.vue +28 -31
- package/src/components/ActionTable/Filters/index.ts +2 -2
- package/src/components/ActionTable/Form/Fields/EditOnClickTextField.vue +71 -0
- package/src/components/ActionTable/Form/Fields/FieldLabel.vue +8 -13
- package/src/components/ActionTable/Form/Fields/FileUploadButton.vue +34 -33
- package/src/components/ActionTable/Form/Fields/MultiFileField.vue +48 -44
- package/src/components/ActionTable/Form/Fields/NumberField.vue +60 -59
- package/src/components/ActionTable/Form/Fields/SelectField.vue +124 -138
- package/src/components/ActionTable/Form/Fields/SelectWithChildrenField.vue +28 -33
- package/src/components/ActionTable/Form/Fields/SingleFileField.vue +15 -15
- package/src/components/ActionTable/Form/Fields/SliderNumberField.vue +45 -0
- package/src/components/ActionTable/Form/Fields/TextField.vue +47 -66
- package/src/components/ActionTable/Form/Fields/index.ts +2 -0
- package/src/components/ActionTable/Form/RenderedForm.vue +50 -13
- package/src/components/ActionTable/Form/Utilities/MaxLengthCounter.vue +17 -0
- package/src/components/ActionTable/Form/Utilities/index.ts +1 -0
- package/src/components/ActionTable/Form/index.ts +1 -0
- package/src/components/ActionTable/Layouts/ActionTableLayout.vue +22 -16
- package/src/components/ActionTable/Toolbars/ActionToolbar.vue +11 -11
- package/src/components/ActionTable/listControls.ts +104 -166
- package/src/components/ActionTable/listHelpers.ts +2 -3
- package/src/components/ActionTable/tableColumns.ts +53 -77
- package/src/components/AuditHistory/AuditHistoryItemValue.vue +26 -26
- package/src/components/PanelsDrawer/PanelsDrawer.vue +17 -4
- package/src/components/PanelsDrawer/PanelsDrawerPanels.vue +6 -11
- package/src/components/PanelsDrawer/PanelsDrawerTabs.vue +20 -20
- package/src/components/Utility/Dialogs/ConfirmActionDialog.vue +39 -0
- package/src/components/Utility/Dialogs/ConfirmDialog.vue +57 -117
- package/src/components/Utility/Dialogs/DialogLayout.vue +77 -0
- package/src/components/Utility/Dialogs/FullscreenCarouselDialog.vue +42 -36
- package/src/components/Utility/Dialogs/InfoDialog.vue +40 -80
- package/src/components/Utility/Dialogs/index.ts +1 -0
- package/src/components/Utility/Files/FilePreview.vue +76 -73
- package/src/components/Utility/Layouts/ContentDrawer.vue +24 -31
- package/src/components/Utility/Tools/ActionVnode.vue +3 -3
- package/src/components/Utility/Tools/RenderVnode.vue +20 -11
- package/src/components/Utility/Transitions/MaxHeightTransition.vue +26 -0
- package/src/components/Utility/Transitions/index.ts +1 -0
- package/src/config/index.ts +36 -31
- package/src/helpers/FileUpload.ts +295 -297
- package/src/helpers/FlashMessages.ts +80 -71
- package/src/helpers/actions.ts +102 -82
- package/src/helpers/download.ts +189 -189
- package/src/helpers/downloadPdf.ts +55 -52
- package/src/helpers/formats.ts +151 -109
- package/src/helpers/index.ts +2 -0
- package/src/helpers/multiFileUpload.ts +72 -58
- package/src/helpers/objectStore.ts +52 -0
- package/src/helpers/request.ts +70 -51
- package/src/helpers/routes.ts +29 -0
- package/src/helpers/storage.ts +7 -3
- package/src/helpers/utils.ts +47 -29
- package/src/styles/quasar-reset.scss +94 -68
- package/src/styles/themes/danx/dialogs.scss +47 -0
- package/src/styles/themes/danx/forms.scss +18 -0
- package/src/styles/themes/danx/index.scss +4 -0
- package/src/types/actions.d.ts +43 -0
- package/src/types/config.d.ts +15 -0
- package/src/types/controls.d.ts +99 -0
- package/src/types/dialogs.d.ts +32 -0
- package/src/types/fields.d.ts +20 -0
- package/src/types/files.d.ts +54 -0
- package/src/types/formats.d.ts +4 -0
- package/src/{components/ActionTable/Form/form.d.ts → types/forms.d.ts} +6 -0
- package/src/types/index.d.ts +12 -0
- package/src/types/requests.d.ts +13 -0
- package/src/types/shared.d.ts +15 -0
- package/src/types/tables.d.ts +27 -0
- package/types/index.d.ts +1 -1
- /package/src/components/ActionTable/Filters/{FilterFieldItem.vue → FilterItem.vue} +0 -0
@@ -1,55 +1,62 @@
|
|
1
1
|
<template>
|
2
2
|
<div
|
3
3
|
class="max-w-full relative overflow-auto"
|
4
|
-
:class="{'p-
|
4
|
+
:class="{'p-2': !readonly}"
|
5
5
|
@dragover.prevent
|
6
6
|
@drop.prevent="onDrop"
|
7
7
|
>
|
8
8
|
<FieldLabel
|
9
9
|
:field="field"
|
10
|
+
:label="label"
|
10
11
|
:show-name="showName"
|
11
12
|
class="text-sm font-semibold"
|
12
13
|
/>
|
13
|
-
|
14
|
+
|
15
|
+
<input
|
14
16
|
v-if="!disable && !readonly"
|
15
|
-
|
17
|
+
ref="file"
|
18
|
+
class="hidden"
|
19
|
+
type="file"
|
20
|
+
multiple
|
21
|
+
@change="onFilesSelected"
|
16
22
|
>
|
17
|
-
<a
|
18
|
-
class="text-blue-600"
|
19
|
-
@click="$refs.file.click()"
|
20
|
-
>Upload</a>
|
21
|
-
<a
|
22
|
-
v-if="uploadedFiles.length > 0"
|
23
|
-
class="ml-3 text-red-900"
|
24
|
-
@click="clearUploadedFiles"
|
25
|
-
>Clear</a>
|
26
|
-
<input
|
27
|
-
ref="file"
|
28
|
-
class="hidden"
|
29
|
-
type="file"
|
30
|
-
multiple
|
31
|
-
@change="onFilesSelected"
|
32
|
-
>
|
33
|
-
</div>
|
34
23
|
|
35
24
|
<div class="max-w-[50em] flex items-stretch justify-start">
|
36
25
|
<FilePreview
|
37
26
|
v-for="file in uploadedFiles"
|
38
27
|
:key="'file-upload-' + file.id"
|
39
|
-
class="w-32 m-2 cursor-pointer bg-gray-200"
|
28
|
+
class="w-32 h-32 m-2 cursor-pointer bg-gray-200"
|
40
29
|
:class="{'border border-dashed border-blue-600': !uploadedFiles.length}"
|
41
|
-
:
|
30
|
+
:file="file"
|
42
31
|
:related-files="uploadedFiles"
|
43
32
|
downloadable
|
44
33
|
:removable="!readonly && !disable"
|
45
34
|
@remove="onRemove(file)"
|
46
35
|
/>
|
47
|
-
<
|
36
|
+
<div
|
48
37
|
v-if="!disable && !readonly"
|
49
|
-
class="w-32 m-2
|
50
|
-
|
51
|
-
|
52
|
-
|
38
|
+
class="dx-add-remove-files w-32 h-32 m-2 rounded-2xl flex flex-col flex-nowrap items-center overflow-hidden cursor-pointer"
|
39
|
+
>
|
40
|
+
<div
|
41
|
+
class="dx-add-file flex-grow p-1 pt-3 flex justify-center items-center bg-green-200 text-green-700 w-full hover:bg-green-100"
|
42
|
+
@click="$refs.file.click()"
|
43
|
+
>
|
44
|
+
<div>
|
45
|
+
<AddFileIcon class="w-10 m-auto" />
|
46
|
+
<div class="mt-1 text-center">
|
47
|
+
Add
|
48
|
+
</div>
|
49
|
+
</div>
|
50
|
+
</div>
|
51
|
+
<div
|
52
|
+
v-if="uploadedFiles.length > 0"
|
53
|
+
class="dx-remove-file flex items-center flex-nowrap p-2 bg-red-200 text-red-800 hover:bg-red-100 w-full justify-center text-xs"
|
54
|
+
@click="clearUploadedFiles"
|
55
|
+
>
|
56
|
+
<RemoveFileIcon class="mr-2 w-3" />
|
57
|
+
Remove All
|
58
|
+
</div>
|
59
|
+
</div>
|
53
60
|
<div
|
54
61
|
v-if="readonly && uploadedFiles.length === 0"
|
55
62
|
class="p-1"
|
@@ -60,32 +67,29 @@
|
|
60
67
|
</div>
|
61
68
|
</template>
|
62
69
|
|
63
|
-
<script setup>
|
70
|
+
<script setup lang="ts">
|
64
71
|
import { onMounted } from "vue";
|
65
72
|
import { useMultiFileUpload } from "../../../../helpers";
|
73
|
+
import { ImageIcon as AddFileIcon, TrashIcon as RemoveFileIcon } from "../../../../svg";
|
74
|
+
import { FormField, UploadedFile } from "../../../../types";
|
66
75
|
import { FilePreview } from "../../../Utility";
|
67
76
|
import FieldLabel from "./FieldLabel";
|
68
77
|
|
69
78
|
const emit = defineEmits(["update:model-value"]);
|
70
|
-
const props = defineProps
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
},
|
79
|
-
showName: Boolean,
|
80
|
-
disable: Boolean,
|
81
|
-
readonly: Boolean
|
82
|
-
});
|
79
|
+
const props = defineProps<{
|
80
|
+
modelValue?: UploadedFile[];
|
81
|
+
field?: FormField;
|
82
|
+
label?: string;
|
83
|
+
showName?: boolean;
|
84
|
+
disable?: boolean;
|
85
|
+
readonly?: boolean;
|
86
|
+
}>();
|
83
87
|
|
84
88
|
const { onComplete, onDrop, onFilesSelected, uploadedFiles, clearUploadedFiles, onRemove } = useMultiFileUpload();
|
85
89
|
onMounted(() => {
|
86
|
-
|
87
|
-
|
88
|
-
|
90
|
+
if (props.modelValue) {
|
91
|
+
uploadedFiles.value = props.modelValue;
|
92
|
+
}
|
89
93
|
});
|
90
94
|
onComplete(() => emit("update:model-value", uploadedFiles.value));
|
91
95
|
</script>
|
@@ -1,13 +1,14 @@
|
|
1
1
|
<template>
|
2
2
|
<QInput
|
3
|
+
class="dx-number-field max-w-full"
|
4
|
+
:class="{'dx-no-prepend-label': hidePrependLabel, 'dx-prepend-label': !hidePrependLabel}"
|
3
5
|
:model-value="numberVal"
|
4
6
|
:data-testid="'number-field-' + fieldOptions.id"
|
5
7
|
:placeholder="fieldOptions.placeholder"
|
6
8
|
outlined
|
7
9
|
dense
|
8
10
|
inputmode="numeric"
|
9
|
-
:input-class="
|
10
|
-
:class="{'no-prepend-icon w-32 max-w-full': hidePrependLabel, 'prepend-label': !hidePrependLabel}"
|
11
|
+
:input-class="inputClass"
|
11
12
|
@update:model-value="onInput"
|
12
13
|
>
|
13
14
|
<template #prepend>
|
@@ -27,33 +28,33 @@ import FieldLabel from "./FieldLabel";
|
|
27
28
|
|
28
29
|
const emit = defineEmits(["update:model-value", "update"]);
|
29
30
|
const props = defineProps({
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
31
|
+
modelValue: {
|
32
|
+
type: [String, Number],
|
33
|
+
default: ""
|
34
|
+
},
|
35
|
+
precision: {
|
36
|
+
type: Number,
|
37
|
+
default: 2
|
38
|
+
},
|
39
|
+
label: {
|
40
|
+
type: String,
|
41
|
+
default: undefined
|
42
|
+
},
|
43
|
+
field: {
|
44
|
+
type: Object,
|
45
|
+
default: null
|
46
|
+
},
|
47
|
+
inputClass: {
|
48
|
+
type: [String, Object],
|
49
|
+
default: ""
|
50
|
+
},
|
51
|
+
delay: {
|
52
|
+
type: Number,
|
53
|
+
default: 1000
|
54
|
+
},
|
55
|
+
hidePrependLabel: Boolean,
|
56
|
+
currency: Boolean,
|
57
|
+
showName: Boolean
|
57
58
|
});
|
58
59
|
|
59
60
|
const numberVal = ref(format(props.modelValue));
|
@@ -62,46 +63,46 @@ watch(() => props.modelValue, () => numberVal.value = format(props.modelValue));
|
|
62
63
|
const fieldOptions = computed(() => props.field || { label: props.label || "", placeholder: "", id: "" });
|
63
64
|
|
64
65
|
function format(number) {
|
65
|
-
|
66
|
+
if (!number && number !== 0 && number !== "0") return number;
|
66
67
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
68
|
+
const minimumFractionDigits = Math.min(props.precision, ("" + number).split(".")[1]?.length || 0);
|
69
|
+
let options = {
|
70
|
+
minimumFractionDigits
|
71
|
+
};
|
71
72
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
73
|
+
if (props.currency) {
|
74
|
+
options = {
|
75
|
+
style: "currency",
|
76
|
+
currency: "USD",
|
77
|
+
minimumFractionDigits
|
78
|
+
};
|
79
|
+
}
|
80
|
+
return fNumber(number, options);
|
80
81
|
}
|
81
82
|
|
82
83
|
const onUpdateDebounced = useDebounceFn((val) => emit("update", val), props.delay);
|
83
84
|
|
84
85
|
function onInput(value) {
|
85
|
-
|
86
|
+
let number = "";
|
86
87
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
88
|
+
// Prevent invalid characters
|
89
|
+
if (value.match(/[^\d.,$]/)) {
|
90
|
+
const oldVal = numberVal.value;
|
91
|
+
// XXX: To get QInput to show only the value we want
|
92
|
+
numberVal.value += " ";
|
93
|
+
return nextTick(() => numberVal.value = oldVal);
|
94
|
+
}
|
94
95
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
96
|
+
if (value !== "") {
|
97
|
+
value = value.replace(/[^\d.]/g, "");
|
98
|
+
number = Number(value);
|
99
|
+
numberVal.value = format(number);
|
100
|
+
}
|
100
101
|
|
101
|
-
|
102
|
-
|
102
|
+
number = number === "" ? undefined : number;
|
103
|
+
emit("update:model-value", number);
|
103
104
|
|
104
|
-
|
105
|
-
|
105
|
+
// Delay the change event, so we only see the value after the user has finished
|
106
|
+
onUpdateDebounced(number);
|
106
107
|
}
|
107
108
|
</script>
|
@@ -16,7 +16,7 @@
|
|
16
16
|
option-value="value"
|
17
17
|
placeholder=""
|
18
18
|
:input-class="{'is-hidden': !isShowing, [inputClass]: true}"
|
19
|
-
class="max-w-full"
|
19
|
+
class="max-w-full dx-select-field"
|
20
20
|
@filter="onFilter"
|
21
21
|
@clear="onClear"
|
22
22
|
@popup-show="onShow"
|
@@ -64,47 +64,33 @@
|
|
64
64
|
</QSelect>
|
65
65
|
</div>
|
66
66
|
</template>
|
67
|
-
<script setup>
|
67
|
+
<script setup lang="ts">
|
68
68
|
import { ChevronDownIcon as DropDownIcon } from "@heroicons/vue/outline";
|
69
|
-
import { QSelect } from "quasar";
|
69
|
+
import { QSelect, QSelectProps } from "quasar";
|
70
70
|
import { computed, isRef, nextTick, ref } from "vue";
|
71
71
|
|
72
|
+
export interface Props extends QSelectProps {
|
73
|
+
modelValue?: any;
|
74
|
+
placeholder?: string;
|
75
|
+
selectionLabel?: string | ((option) => string);
|
76
|
+
chipLimit?: number;
|
77
|
+
inputClass?: string;
|
78
|
+
selectionClass?: string;
|
79
|
+
options?: unknown[];
|
80
|
+
filterable?: boolean;
|
81
|
+
filterFn?: (val: string) => void;
|
82
|
+
}
|
83
|
+
|
72
84
|
const emit = defineEmits(["update:model-value", "search", "update"]);
|
73
|
-
const props = defineProps({
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
},
|
83
|
-
selectionLabel: {
|
84
|
-
type: String,
|
85
|
-
default: null
|
86
|
-
},
|
87
|
-
chipLimit: {
|
88
|
-
type: Number,
|
89
|
-
default: 3
|
90
|
-
},
|
91
|
-
inputClass: {
|
92
|
-
type: String,
|
93
|
-
default: ""
|
94
|
-
},
|
95
|
-
selectionClass: {
|
96
|
-
type: String,
|
97
|
-
default: ""
|
98
|
-
},
|
99
|
-
options: {
|
100
|
-
type: Array,
|
101
|
-
default: () => []
|
102
|
-
},
|
103
|
-
filterable: Boolean,
|
104
|
-
filterFn: {
|
105
|
-
type: Function,
|
106
|
-
default: null
|
107
|
-
}
|
85
|
+
const props = withDefaults(defineProps<Props>(), {
|
86
|
+
modelValue: undefined,
|
87
|
+
placeholder: "",
|
88
|
+
selectionLabel: null,
|
89
|
+
chipLimit: 3,
|
90
|
+
inputClass: "",
|
91
|
+
selectionClass: "",
|
92
|
+
options: () => [],
|
93
|
+
filterFn: null
|
108
94
|
});
|
109
95
|
|
110
96
|
const selectField = ref(null);
|
@@ -119,27 +105,27 @@ const isShowing = ref(false);
|
|
119
105
|
* @type {ComputedRef<{selectionLabel: string, label: string, value: string|*}[]>}
|
120
106
|
*/
|
121
107
|
const computedOptions = computed(() => {
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
108
|
+
let options = props.options;
|
109
|
+
if (props.placeholder && !props.multiple && !props.filterable) {
|
110
|
+
options = [{ label: props.placeholder, value: null }, ...props.options];
|
111
|
+
}
|
112
|
+
options = options.map((o) => {
|
113
|
+
let opt = isRef(o) ? o.value : o;
|
114
|
+
return {
|
115
|
+
label: resolveLabel(opt),
|
116
|
+
value: resolveValue(opt),
|
117
|
+
selectionLabel: resolveSelectionLabel(opt)
|
118
|
+
};
|
119
|
+
});
|
120
|
+
return options;
|
135
121
|
});
|
136
122
|
|
137
123
|
const filteredOptions = computed(() => {
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
124
|
+
if (filter.value && !props.filterFn) {
|
125
|
+
return computedOptions.value.filter(o => o.label.toLocaleLowerCase().indexOf(filter.value?.toLowerCase()) > -1);
|
126
|
+
} else {
|
127
|
+
return computedOptions.value;
|
128
|
+
}
|
143
129
|
});
|
144
130
|
|
145
131
|
/**
|
@@ -147,14 +133,14 @@ const filteredOptions = computed(() => {
|
|
147
133
|
* @type {ComputedRef<unknown>}
|
148
134
|
*/
|
149
135
|
const selectedValue = computed(() => {
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
136
|
+
if (props.multiple) {
|
137
|
+
const arrVal = Array.isArray(props.modelValue) ? props.modelValue : [];
|
138
|
+
return arrVal.map((v) => {
|
139
|
+
return v === null ? "__null__" : v;
|
140
|
+
}) || [];
|
141
|
+
} else {
|
142
|
+
return props.modelValue === null ? "__null__" : props.modelValue;
|
143
|
+
}
|
158
144
|
});
|
159
145
|
|
160
146
|
/**
|
@@ -162,13 +148,13 @@ const selectedValue = computed(() => {
|
|
162
148
|
* @type {ComputedRef<*>}
|
163
149
|
*/
|
164
150
|
const selectedOptions = computed(() => {
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
151
|
+
let values = selectedValue.value;
|
152
|
+
if (!props.multiple) {
|
153
|
+
values = (values || values === 0) ? [values] : [];
|
154
|
+
}
|
155
|
+
return computedOptions.value.filter((o) => {
|
156
|
+
return values.includes(o.value) || values.map(v => typeof v === "object" && v.id).includes(o.value?.id);
|
157
|
+
});
|
172
158
|
});
|
173
159
|
|
174
160
|
/**
|
@@ -177,12 +163,12 @@ const selectedOptions = computed(() => {
|
|
177
163
|
* @type {ComputedRef<unknown>}
|
178
164
|
*/
|
179
165
|
const selectedLabel = computed(() => {
|
180
|
-
|
166
|
+
if (props.filterable && isShowing.value) return "";
|
181
167
|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
168
|
+
if (!selectedOptions.value || selectedOptions.value.length === 0) {
|
169
|
+
return props.placeholder || "(Select Option)";
|
170
|
+
}
|
171
|
+
return selectedOptions.value[0].selectionLabel;
|
186
172
|
});
|
187
173
|
|
188
174
|
/**
|
@@ -190,7 +176,7 @@ const selectedLabel = computed(() => {
|
|
190
176
|
* @type {ComputedRef<*>}
|
191
177
|
*/
|
192
178
|
const chipOptions = computed(() => {
|
193
|
-
|
179
|
+
return selectedOptions.value.slice(0, props.chipLimit);
|
194
180
|
});
|
195
181
|
|
196
182
|
/**
|
@@ -199,16 +185,16 @@ const chipOptions = computed(() => {
|
|
199
185
|
* @returns {*|string}
|
200
186
|
*/
|
201
187
|
function resolveLabel(option) {
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
188
|
+
if (typeof option === "string") {
|
189
|
+
return option;
|
190
|
+
}
|
191
|
+
if (typeof props.optionLabel === "string") {
|
192
|
+
return option[props.optionLabel];
|
193
|
+
}
|
194
|
+
if (typeof props.optionLabel === "function") {
|
195
|
+
return props.optionLabel(option);
|
196
|
+
}
|
197
|
+
return option?.label;
|
212
198
|
}
|
213
199
|
|
214
200
|
/**
|
@@ -218,16 +204,16 @@ function resolveLabel(option) {
|
|
218
204
|
* @returns {*|{default: null, type: String | StringConstructor}|string}
|
219
205
|
*/
|
220
206
|
function resolveSelectionLabel(option) {
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
207
|
+
if (typeof option === "string") {
|
208
|
+
return option;
|
209
|
+
}
|
210
|
+
if (typeof props.selectionLabel === "string") {
|
211
|
+
return option[props.selectionLabel];
|
212
|
+
}
|
213
|
+
if (typeof props.selectionLabel === "function") {
|
214
|
+
return props.selectionLabel(option);
|
215
|
+
}
|
216
|
+
return option?.selectionLabel || option?.label;
|
231
217
|
}
|
232
218
|
|
233
219
|
/**
|
@@ -236,17 +222,17 @@ function resolveSelectionLabel(option) {
|
|
236
222
|
* @returns {string|*|string}
|
237
223
|
*/
|
238
224
|
function resolveValue(option) {
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
225
|
+
if (!option || typeof option === "string") {
|
226
|
+
return option;
|
227
|
+
}
|
228
|
+
let value = option.value;
|
229
|
+
if (typeof props.optionValue === "string") {
|
230
|
+
value = option[props.optionValue];
|
231
|
+
} else if (typeof props.optionValue === "function") {
|
232
|
+
value = props.optionValue(option);
|
233
|
+
}
|
234
|
+
// Note the __null__ special case here. See the onUpdate function for more details
|
235
|
+
return value === null ? "__null__" : value;
|
250
236
|
}
|
251
237
|
|
252
238
|
/**
|
@@ -256,14 +242,14 @@ function resolveValue(option) {
|
|
256
242
|
* @param value
|
257
243
|
*/
|
258
244
|
function onUpdate(value) {
|
259
|
-
|
260
|
-
|
261
|
-
|
245
|
+
if (Array.isArray(value)) {
|
246
|
+
value = value.map((v) => v === "__null__" ? null : v);
|
247
|
+
}
|
262
248
|
|
263
|
-
|
249
|
+
value = value === "__null__" ? null : value;
|
264
250
|
|
265
|
-
|
266
|
-
|
251
|
+
emit("update", value);
|
252
|
+
emit("update:model-value", value);
|
267
253
|
}
|
268
254
|
|
269
255
|
/** XXX: This tells us when we should apply the filter. QSelect likes to trigger a new filter everytime you open the dropdown
|
@@ -277,19 +263,19 @@ const shouldFilter = ref(false);
|
|
277
263
|
* @param update
|
278
264
|
*/
|
279
265
|
async function onFilter(val, update) {
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
266
|
+
if (!props.filterFn) {
|
267
|
+
filter.value = val;
|
268
|
+
await nextTick(update);
|
269
|
+
} else {
|
270
|
+
update();
|
271
|
+
if (shouldFilter.value === false) return;
|
272
|
+
if (val !== null && val !== filter.value) {
|
273
|
+
filter.value = val;
|
274
|
+
if (props.filterFn) {
|
275
|
+
await props.filterFn(val);
|
276
|
+
}
|
277
|
+
}
|
278
|
+
}
|
293
279
|
}
|
294
280
|
|
295
281
|
/**
|
@@ -297,29 +283,29 @@ async function onFilter(val, update) {
|
|
297
283
|
* See the onUpdate function for more details
|
298
284
|
*/
|
299
285
|
function onClear() {
|
300
|
-
|
301
|
-
|
286
|
+
emit("update:model-value", undefined);
|
287
|
+
emit("update", undefined);
|
302
288
|
}
|
303
289
|
|
304
290
|
/**
|
305
291
|
* Handle behavior when showing the dropdown
|
306
292
|
*/
|
307
293
|
function onShow() {
|
308
|
-
|
294
|
+
isShowing.value = true;
|
309
295
|
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
296
|
+
// XXX: See description on shouldFilter declaration. Only allow filtering after dropdown is ALREADY opened
|
297
|
+
shouldFilter.value = false;
|
298
|
+
nextTick(() => {
|
299
|
+
shouldFilter.value = true;
|
300
|
+
selectField.value.focus();
|
301
|
+
});
|
316
302
|
}
|
317
303
|
|
318
304
|
/**
|
319
305
|
* Handle behavior when hiding the dropdown
|
320
306
|
*/
|
321
307
|
function onHide() {
|
322
|
-
|
323
|
-
|
308
|
+
isShowing.value = false;
|
309
|
+
shouldFilter.value = false;
|
324
310
|
}
|
325
311
|
</script>
|