quasar-ui-danx 0.0.11 → 0.0.13
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/index.css +5 -0
- package/dist/index.min.css +5 -0
- package/dist/index.rtl.css +5 -0
- package/dist/index.rtl.min.css +5 -0
- package/package.json +6 -1
- package/src/components/ActionTable/ActionTable.vue +49 -41
- package/src/components/ActionTable/BatchActionMenu.vue +20 -20
- package/src/components/ActionTable/EmptyTableState.vue +5 -5
- package/src/components/ActionTable/Filters/CollapsableFiltersSidebar.vue +11 -11
- package/src/components/ActionTable/Filters/FilterGroupItem.vue +7 -7
- package/src/components/ActionTable/Filters/FilterGroupList.vue +29 -29
- package/src/components/ActionTable/Filters/FilterListToggle.vue +15 -15
- package/src/components/ActionTable/Filters/FilterableField.vue +82 -80
- package/src/components/ActionTable/Filters/index.ts +5 -0
- package/src/components/ActionTable/Form/Fields/BooleanField.vue +13 -13
- package/src/components/ActionTable/Form/Fields/ConfirmPasswordField.vue +11 -11
- package/src/components/ActionTable/Form/Fields/DateField.vue +13 -13
- package/src/components/ActionTable/Form/Fields/DateRangeField.vue +25 -25
- package/src/components/ActionTable/Form/Fields/DateTimeField.vue +21 -21
- package/src/components/ActionTable/Form/Fields/DateTimePicker.vue +23 -23
- package/src/components/ActionTable/Form/Fields/FileUploadButton.vue +31 -31
- package/src/components/ActionTable/Form/Fields/InlineDateTimeField.vue +19 -19
- package/src/components/ActionTable/Form/Fields/IntegerField.vue +7 -7
- package/src/components/ActionTable/Form/Fields/LabelValueBlock.vue +22 -0
- package/src/components/ActionTable/Form/Fields/LabeledInput.vue +19 -19
- package/src/components/ActionTable/Form/Fields/MultiFileField.vue +40 -40
- package/src/components/ActionTable/Form/Fields/MultiKeywordField.vue +23 -23
- package/src/components/ActionTable/Form/Fields/NewPasswordField.vue +10 -10
- package/src/components/ActionTable/Form/Fields/NumberField.vue +29 -29
- package/src/components/ActionTable/Form/Fields/NumberRangeField.vue +33 -33
- package/src/components/ActionTable/Form/Fields/SelectDrawer.vue +36 -36
- package/src/components/ActionTable/Form/Fields/SelectField.vue +66 -66
- package/src/components/ActionTable/Form/Fields/SelectWithChildrenField.vue +23 -23
- package/src/components/ActionTable/Form/Fields/SingleFileField.vue +32 -32
- package/src/components/ActionTable/Form/Fields/TextField.vue +36 -36
- package/src/components/ActionTable/Form/Fields/WysiwygField.vue +16 -16
- package/src/components/ActionTable/Form/Fields/index.ts +23 -23
- package/src/components/ActionTable/Form/RenderedForm.vue +27 -25
- package/src/components/ActionTable/Form/index.ts +2 -0
- package/src/components/ActionTable/TableSummaryRow.vue +33 -33
- package/src/components/ActionTable/index.ts +8 -13
- package/src/components/ActionTable/listActions.ts +340 -339
- package/src/components/ActionTable/listHelpers.ts +74 -0
- package/src/components/ActionTable/tableColumns.ts +56 -56
- package/src/components/DragAndDrop/HandleDraggable.vue +29 -29
- package/src/components/DragAndDrop/ListItemDraggable.vue +10 -10
- package/src/components/DragAndDrop/index.ts +0 -1
- package/src/components/DragAndDrop/listDragAndDrop.ts +1 -1
- package/src/components/Utility/CollapsableSidebar.vue +35 -35
- package/src/components/Utility/ContentDrawer.vue +20 -20
- package/src/components/Utility/Dialogs/ConfirmDialog.vue +55 -55
- package/src/components/Utility/Dialogs/FullScreenDialog.vue +18 -18
- package/src/components/Utility/Dialogs/FullscreenCarouselDialog.vue +105 -0
- package/src/components/Utility/Dialogs/InfoDialog.vue +10 -10
- package/src/components/Utility/Dialogs/InputDialog.vue +13 -13
- package/src/components/Utility/ImagePreview.vue +192 -0
- package/src/components/Utility/Popover/PopoverMenu.vue +64 -0
- package/src/components/Utility/Transitions/StaggeredListTransition.vue +15 -15
- package/src/components/Utility/index.ts +11 -9
- package/src/components/index.ts +1 -1
- package/src/helpers/FileUpload.ts +274 -273
- package/src/helpers/compatibility.ts +45 -45
- package/src/helpers/date.ts +2 -2
- package/src/helpers/download.ts +166 -158
- package/src/helpers/downloadPdf.ts +48 -48
- package/src/helpers/files.ts +42 -42
- package/src/helpers/index.ts +2 -0
- package/src/helpers/multiFileUpload.ts +56 -56
- package/src/helpers/singleFileUpload.ts +49 -49
- package/src/index.esm.js +3 -4
- package/src/svg/FilterIcon.svg +7 -0
- package/src/svg/ImageIcon.svg +30 -0
- package/src/svg/PdfIcon.svg +21 -0
- package/src/svg/PercentIcon.svg +13 -0
- package/src/svg/TrashIcon.svg +15 -0
- package/src/svg/XIcon.svg +18 -0
- package/src/svg/index.ts +8 -0
- package/src/vendor/tinymce-config.ts +1 -0
- package/src/vue-plugin.js +7 -4
- package/tsconfig.json +18 -14
- package/src/components/ActionTable/tableHelpers.ts +0 -83
- package/src/components/DragAndDrop/Icons/index.ts +0 -2
- /package/src/{components/DragAndDrop/Icons → svg}/DragHandleDotsIcon.svg +0 -0
- /package/src/{components/DragAndDrop/Icons → svg}/DragHandleIcon.svg +0 -0
@@ -1,15 +1,15 @@
|
|
1
1
|
<template>
|
2
2
|
<div>
|
3
3
|
<div
|
4
|
-
|
5
|
-
|
4
|
+
v-if="label"
|
5
|
+
class="font-bold text-xs mb-2"
|
6
6
|
>
|
7
7
|
{{ label }}
|
8
8
|
</div>
|
9
9
|
<div class="flex items-center flex-nowrap cursor-pointer">
|
10
10
|
<component
|
11
|
-
|
12
|
-
|
11
|
+
:is="previewIcon"
|
12
|
+
class="w-5 text-blue-base"
|
13
13
|
/>
|
14
14
|
<div class="text-sm ml-3 hover:text-blue-base whitespace-nowrap">
|
15
15
|
<template v-if="range">
|
@@ -20,31 +20,31 @@
|
|
20
20
|
</template>
|
21
21
|
</div>
|
22
22
|
</div>
|
23
|
-
<
|
23
|
+
<q-popup-proxy>
|
24
24
|
<NumberField
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
v-model="range.from"
|
26
|
+
:field="minField"
|
27
|
+
@update:model-value="onSave"
|
28
28
|
/>
|
29
29
|
<NumberField
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
v-model="range.to"
|
31
|
+
class="mt-2"
|
32
|
+
:field="maxField"
|
33
|
+
@update:model-value="onSave"
|
34
34
|
/>
|
35
|
-
|
35
|
+
</q-popup-proxy>
|
36
36
|
</div>
|
37
37
|
</template>
|
38
38
|
|
39
39
|
<script setup>
|
40
|
-
import {
|
41
|
-
import {
|
42
|
-
import {
|
43
|
-
import
|
44
|
-
import {
|
45
|
-
import
|
40
|
+
import { CurrencyDollarIcon as CurrencyIcon, HashtagIcon as NumberIcon } from '@heroicons/vue/outline';
|
41
|
+
import { fCurrency, fNumber, fPercent } from '@ui/helpers';
|
42
|
+
import { PercentIcon } from '@ui/svg';
|
43
|
+
import { useDebounceFn } from '@vueuse/core';
|
44
|
+
import { computed, ref, watch } from 'vue';
|
45
|
+
import NumberField from './NumberField';
|
46
46
|
|
47
|
-
const emit = defineEmits([
|
47
|
+
const emit = defineEmits(['update:model-value']);
|
48
48
|
const props = defineProps({
|
49
49
|
modelValue: {
|
50
50
|
type: Object,
|
@@ -68,28 +68,28 @@ const props = defineProps({
|
|
68
68
|
|
69
69
|
const symbol = computed(() => {
|
70
70
|
if (props.currency) {
|
71
|
-
return
|
71
|
+
return '$';
|
72
72
|
} else if (props.percent) {
|
73
|
-
return
|
73
|
+
return '%';
|
74
74
|
} else {
|
75
|
-
return
|
75
|
+
return '';
|
76
76
|
}
|
77
77
|
});
|
78
78
|
const minField = computed(() => {
|
79
79
|
return {
|
80
|
-
id:
|
81
|
-
name:
|
82
|
-
label:
|
83
|
-
placeholder:
|
80
|
+
id: 'min-field',
|
81
|
+
name: 'from',
|
82
|
+
label: 'Min' + symbol.value,
|
83
|
+
placeholder: '0'
|
84
84
|
};
|
85
85
|
});
|
86
86
|
|
87
87
|
const maxField = computed(() => {
|
88
88
|
return {
|
89
|
-
id:
|
90
|
-
name:
|
91
|
-
label:
|
92
|
-
placeholder:
|
89
|
+
id: 'max-field',
|
90
|
+
name: 'to',
|
91
|
+
label: 'Max' + symbol.value,
|
92
|
+
placeholder: 'No Limit'
|
93
93
|
};
|
94
94
|
});
|
95
95
|
|
@@ -112,7 +112,7 @@ setRange(props.modelValue || { from: undefined, to: undefined });
|
|
112
112
|
* @returns {string}
|
113
113
|
*/
|
114
114
|
function formatNum(num) {
|
115
|
-
if (num === undefined) return
|
115
|
+
if (num === undefined) return 'No Limit';
|
116
116
|
if (props.currency) {
|
117
117
|
return fCurrency(num);
|
118
118
|
}
|
@@ -134,7 +134,7 @@ const onSave = useDebounceFn(() => {
|
|
134
134
|
from: (range.value.from ? range.value.from * multiplier : undefined),
|
135
135
|
to: (range.value.to ? range.value.to * multiplier : undefined)
|
136
136
|
};
|
137
|
-
emit(
|
137
|
+
emit('update:model-value', newVal);
|
138
138
|
}
|
139
139
|
}, props.debounce);
|
140
140
|
</script>
|
@@ -1,36 +1,36 @@
|
|
1
1
|
<template>
|
2
2
|
<div>
|
3
3
|
<ContentDrawer
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
v-model:show="showDrawer"
|
5
|
+
content-class=""
|
6
|
+
position="bottom"
|
7
|
+
:title="'Filter ' + label"
|
8
8
|
>
|
9
9
|
<div
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
v-for="option in formattedOptions"
|
11
|
+
:key="'select-drawer-' + option.value"
|
12
|
+
:data-dusk="'drawer-opt-' + option.value"
|
13
|
+
class="cursor-pointer hover:bg-gray-light px-8 py-3 flex items-center border-b border-gray-light"
|
14
|
+
@click="toggleSelect(option)"
|
15
15
|
>
|
16
|
-
<
|
17
|
-
|
18
|
-
|
16
|
+
<q-checkbox
|
17
|
+
:model-value="isSelected(option)"
|
18
|
+
class="mr-2"
|
19
19
|
/>
|
20
20
|
<slot
|
21
|
-
|
22
|
-
|
21
|
+
name="option"
|
22
|
+
:opt="option"
|
23
23
|
>{{ option.label }}
|
24
24
|
</slot>
|
25
25
|
</div>
|
26
26
|
</ContentDrawer>
|
27
27
|
|
28
|
-
<
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
28
|
+
<q-chip
|
29
|
+
ref="select"
|
30
|
+
outline
|
31
|
+
clickable
|
32
|
+
size="16px"
|
33
|
+
@click="showDrawer = true"
|
34
34
|
>
|
35
35
|
<slot name="selected">
|
36
36
|
<slot name="label">{{ label }}: </slot>
|
@@ -39,7 +39,7 @@
|
|
39
39
|
<template v-if="multiple">
|
40
40
|
{{ getOptionLabel(modelValue[0]) }}
|
41
41
|
<template
|
42
|
-
|
42
|
+
v-if="modelValue.length > 1"
|
43
43
|
>+ {{ modelValue.length - 1 }}
|
44
44
|
</template
|
45
45
|
>
|
@@ -53,15 +53,15 @@
|
|
53
53
|
<slot name="placeholder">{{ placeholder }}</slot>
|
54
54
|
</template>
|
55
55
|
</slot>
|
56
|
-
|
56
|
+
</q-chip>
|
57
57
|
</div>
|
58
58
|
</template>
|
59
59
|
|
60
60
|
<script setup>
|
61
|
-
import { ContentDrawer } from
|
62
|
-
import { computed, ref } from
|
61
|
+
import { ContentDrawer } from '@ui/components';
|
62
|
+
import { computed, ref } from 'vue';
|
63
63
|
|
64
|
-
const emit = defineEmits([
|
64
|
+
const emit = defineEmits(['update:modelValue']);
|
65
65
|
const props = defineProps({
|
66
66
|
modelValue: {
|
67
67
|
type: [Object, String, Array, null],
|
@@ -74,24 +74,24 @@ const props = defineProps({
|
|
74
74
|
multiple: Boolean,
|
75
75
|
label: {
|
76
76
|
type: String,
|
77
|
-
default:
|
77
|
+
default: 'Select'
|
78
78
|
},
|
79
79
|
placeholder: {
|
80
80
|
type: String,
|
81
|
-
default:
|
81
|
+
default: 'All'
|
82
82
|
}
|
83
83
|
});
|
84
84
|
|
85
85
|
const showDrawer = ref(false);
|
86
86
|
const formattedOptions = computed(() =>
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
87
|
+
props.options.map((opt) =>
|
88
|
+
typeof opt === 'string'
|
89
|
+
? {
|
90
|
+
label: opt,
|
91
|
+
value: opt
|
92
|
+
}
|
93
|
+
: opt
|
94
|
+
)
|
95
95
|
);
|
96
96
|
|
97
97
|
function getOptionValue(option) {
|
@@ -131,6 +131,6 @@ function toggleSelect(option) {
|
|
131
131
|
}
|
132
132
|
}
|
133
133
|
|
134
|
-
emit(
|
134
|
+
emit('update:modelValue', selection);
|
135
135
|
}
|
136
136
|
</script>
|
@@ -1,73 +1,73 @@
|
|
1
1
|
<template>
|
2
2
|
<div>
|
3
|
-
<
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
3
|
+
<q-select
|
4
|
+
ref="selectField"
|
5
|
+
v-bind="$props"
|
6
|
+
:model-value="selectedValue"
|
7
|
+
outlined
|
8
|
+
hide-dropdown-icon
|
9
|
+
dense
|
10
|
+
emit-value
|
11
|
+
:use-input="filterable"
|
12
|
+
:hide-selected="filterable && isShowing && !$props.multiple"
|
13
|
+
:input-debounce="100"
|
14
|
+
:options="filteredOptions"
|
15
|
+
option-label="label"
|
16
|
+
option-value="value"
|
17
|
+
placeholder=""
|
18
|
+
:input-class="{'is-hidden': !isShowing, [inputClass]: true}"
|
19
|
+
class="max-w-full"
|
20
|
+
@filter="onFilter"
|
21
|
+
@clear="onClear"
|
22
|
+
@popup-show="onShow"
|
23
|
+
@popup-hide="onHide"
|
24
|
+
@update:model-value="onUpdate"
|
25
25
|
>
|
26
26
|
<template #append>
|
27
27
|
<DropDownIcon
|
28
|
-
|
29
|
-
|
28
|
+
class="w-4 transition"
|
29
|
+
:class="isShowing ? 'rotate-180' : ''"
|
30
30
|
/>
|
31
31
|
</template>
|
32
32
|
<template #selected>
|
33
33
|
<div
|
34
|
-
|
35
|
-
|
36
|
-
|
34
|
+
v-if="$props.multiple"
|
35
|
+
class="flex gap-y-1 overflow-hidden"
|
36
|
+
:class="{'flex-nowrap gap-y-0': chipLimit === 1, [selectionClass]: true}"
|
37
37
|
>
|
38
38
|
<template v-if="chipOptions.length > 0">
|
39
|
-
<
|
40
|
-
|
41
|
-
|
42
|
-
|
39
|
+
<q-chip
|
40
|
+
v-for="chipOption in chipOptions"
|
41
|
+
:key="'selected-' + chipOption.label"
|
42
|
+
class="!mr-1"
|
43
43
|
>{{ chipOption.label }}
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
44
|
+
</q-chip>
|
45
|
+
<q-chip
|
46
|
+
v-if="selectedOptions.length > chipOptions.length"
|
47
|
+
class="!mr-1"
|
48
|
+
>
|
49
|
+
+{{ selectedOptions.length - chipOptions.length }}
|
50
|
+
</q-chip>
|
51
51
|
</template>
|
52
52
|
<template v-else>
|
53
53
|
{{ placeholder }}
|
54
54
|
</template>
|
55
55
|
</div>
|
56
56
|
<div
|
57
|
-
|
58
|
-
|
57
|
+
v-else
|
58
|
+
:class="selectionClass"
|
59
59
|
>{{ selectedLabel }}
|
60
60
|
</div>
|
61
61
|
</template>
|
62
|
-
|
62
|
+
</q-select>
|
63
63
|
</div>
|
64
64
|
</template>
|
65
65
|
<script setup>
|
66
|
-
import { ChevronDownIcon as DropDownIcon } from
|
67
|
-
import { QSelect } from
|
68
|
-
import { computed, isRef, nextTick, ref } from
|
66
|
+
import { ChevronDownIcon as DropDownIcon } from '@heroicons/vue/outline';
|
67
|
+
import { QSelect } from 'quasar';
|
68
|
+
import { computed, isRef, nextTick, ref } from 'vue';
|
69
69
|
|
70
|
-
const emit = defineEmits([
|
70
|
+
const emit = defineEmits(['update:model-value', 'search']);
|
71
71
|
const props = defineProps({
|
72
72
|
...QSelect.props,
|
73
73
|
modelValue: {
|
@@ -76,7 +76,7 @@ const props = defineProps({
|
|
76
76
|
},
|
77
77
|
placeholder: {
|
78
78
|
type: String,
|
79
|
-
default:
|
79
|
+
default: ''
|
80
80
|
},
|
81
81
|
selectionLabel: {
|
82
82
|
type: String,
|
@@ -88,11 +88,11 @@ const props = defineProps({
|
|
88
88
|
},
|
89
89
|
inputClass: {
|
90
90
|
type: String,
|
91
|
-
default:
|
91
|
+
default: ''
|
92
92
|
},
|
93
93
|
selectionClass: {
|
94
94
|
type: String,
|
95
|
-
default:
|
95
|
+
default: ''
|
96
96
|
},
|
97
97
|
options: {
|
98
98
|
type: Array,
|
@@ -148,10 +148,10 @@ const selectedValue = computed(() => {
|
|
148
148
|
if (props.multiple) {
|
149
149
|
const arrVal = Array.isArray(props.modelValue) ? props.modelValue : [];
|
150
150
|
return arrVal.map((v) => {
|
151
|
-
return v === null ?
|
151
|
+
return v === null ? '__null__' : v;
|
152
152
|
}) || [];
|
153
153
|
} else {
|
154
|
-
return props.modelValue === null ?
|
154
|
+
return props.modelValue === null ? '__null__' : props.modelValue;
|
155
155
|
}
|
156
156
|
});
|
157
157
|
|
@@ -165,7 +165,7 @@ const selectedOptions = computed(() => {
|
|
165
165
|
values = (values || values === 0) ? [values] : [];
|
166
166
|
}
|
167
167
|
return computedOptions.value.filter((o) => {
|
168
|
-
return values.includes(o.value) || values.map(v => typeof v ===
|
168
|
+
return values.includes(o.value) || values.map(v => typeof v === 'object' && v.id).includes(o.value?.id);
|
169
169
|
});
|
170
170
|
});
|
171
171
|
|
@@ -175,10 +175,10 @@ const selectedOptions = computed(() => {
|
|
175
175
|
* @type {ComputedRef<unknown>}
|
176
176
|
*/
|
177
177
|
const selectedLabel = computed(() => {
|
178
|
-
if (props.filterable && isShowing.value) return
|
178
|
+
if (props.filterable && isShowing.value) return '';
|
179
179
|
|
180
180
|
if (!selectedOptions.value || selectedOptions.value.length === 0) {
|
181
|
-
return props.placeholder ||
|
181
|
+
return props.placeholder || '(Select Option)';
|
182
182
|
}
|
183
183
|
return selectedOptions.value[0].selectionLabel;
|
184
184
|
});
|
@@ -197,13 +197,13 @@ const chipOptions = computed(() => {
|
|
197
197
|
* @returns {*|string}
|
198
198
|
*/
|
199
199
|
function resolveLabel(option) {
|
200
|
-
if (typeof option ===
|
200
|
+
if (typeof option === 'string') {
|
201
201
|
return option;
|
202
202
|
}
|
203
|
-
if (typeof props.optionLabel ===
|
203
|
+
if (typeof props.optionLabel === 'string') {
|
204
204
|
return option[props.optionLabel];
|
205
205
|
}
|
206
|
-
if (typeof props.optionLabel ===
|
206
|
+
if (typeof props.optionLabel === 'function') {
|
207
207
|
return props.optionLabel(option);
|
208
208
|
}
|
209
209
|
return option?.label;
|
@@ -216,13 +216,13 @@ function resolveLabel(option) {
|
|
216
216
|
* @returns {*|{default: null, type: String | StringConstructor}|string}
|
217
217
|
*/
|
218
218
|
function resolveSelectionLabel(option) {
|
219
|
-
if (typeof option ===
|
219
|
+
if (typeof option === 'string') {
|
220
220
|
return option;
|
221
221
|
}
|
222
|
-
if (typeof props.selectionLabel ===
|
222
|
+
if (typeof props.selectionLabel === 'string') {
|
223
223
|
return option[props.selectionLabel];
|
224
224
|
}
|
225
|
-
if (typeof props.selectionLabel ===
|
225
|
+
if (typeof props.selectionLabel === 'function') {
|
226
226
|
return props.selectionLabel(option);
|
227
227
|
}
|
228
228
|
return option?.selectionLabel || option?.label;
|
@@ -234,17 +234,17 @@ function resolveSelectionLabel(option) {
|
|
234
234
|
* @returns {string|*|string}
|
235
235
|
*/
|
236
236
|
function resolveValue(option) {
|
237
|
-
if (typeof option ===
|
237
|
+
if (typeof option === 'string') {
|
238
238
|
return option;
|
239
239
|
}
|
240
240
|
let value = option.value;
|
241
|
-
if (typeof props.optionValue ===
|
241
|
+
if (typeof props.optionValue === 'string') {
|
242
242
|
value = option[props.optionValue];
|
243
|
-
} else if (typeof props.optionValue ===
|
243
|
+
} else if (typeof props.optionValue === 'function') {
|
244
244
|
value = props.optionValue(option);
|
245
245
|
}
|
246
246
|
// Note the __null__ special case here. See the onUpdate function for more details
|
247
|
-
return value === null ?
|
247
|
+
return value === null ? '__null__' : value;
|
248
248
|
}
|
249
249
|
|
250
250
|
/**
|
@@ -255,9 +255,9 @@ function resolveValue(option) {
|
|
255
255
|
*/
|
256
256
|
function onUpdate(value) {
|
257
257
|
if (Array.isArray(value)) {
|
258
|
-
value = value.map((v) => v ===
|
258
|
+
value = value.map((v) => v === '__null__' ? null : v);
|
259
259
|
}
|
260
|
-
emit(
|
260
|
+
emit('update:model-value', value === '__null__' ? null : value);
|
261
261
|
}
|
262
262
|
|
263
263
|
/** XXX: This tells us when we should apply the filter. QSelect likes to trigger a new filter everytime you open the dropdown
|
@@ -291,7 +291,7 @@ async function onFilter(val, update) {
|
|
291
291
|
* See the onUpdate function for more details
|
292
292
|
*/
|
293
293
|
function onClear() {
|
294
|
-
emit(
|
294
|
+
emit('update:model-value', undefined);
|
295
295
|
}
|
296
296
|
|
297
297
|
/**
|
@@ -4,35 +4,35 @@
|
|
4
4
|
<div class="text-gray-silver">No options available</div>
|
5
5
|
</template>
|
6
6
|
<SelectField
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
7
|
+
v-model="selectedOption"
|
8
|
+
:options="options"
|
9
|
+
:label="label"
|
10
|
+
:placeholder="placeholder"
|
11
|
+
:option-value="opt => opt"
|
12
|
+
:loading="loading"
|
13
|
+
@update:model-value="onSelectOption"
|
14
14
|
/>
|
15
15
|
<div v-if="selectedOption">
|
16
|
-
<
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
16
|
+
<q-checkbox
|
17
|
+
v-for="child in selectedOption.children"
|
18
|
+
:key="child.id"
|
19
|
+
:model-value="selectedChildren.includes(child.id)"
|
20
|
+
:field="child"
|
21
|
+
class="mt-3"
|
22
|
+
@update:model-value="onSelectChild(child)"
|
23
23
|
>
|
24
24
|
<div>{{ child.label }}</div>
|
25
25
|
<div class="text-xs text-gray-silver">{{ child.name }}</div>
|
26
|
-
|
26
|
+
</q-checkbox>
|
27
27
|
</div>
|
28
28
|
</div>
|
29
29
|
</template>
|
30
30
|
<script setup>
|
31
|
-
import
|
32
|
-
import {
|
33
|
-
import
|
31
|
+
import { remove } from '@ui/helpers/array';
|
32
|
+
import { ref, watch } from 'vue';
|
33
|
+
import SelectField from './SelectField';
|
34
34
|
|
35
|
-
const emit = defineEmits([
|
35
|
+
const emit = defineEmits(['update:model-value']);
|
36
36
|
const props = defineProps({
|
37
37
|
modelValue: {
|
38
38
|
type: Array,
|
@@ -40,11 +40,11 @@ const props = defineProps({
|
|
40
40
|
},
|
41
41
|
label: {
|
42
42
|
type: String,
|
43
|
-
default:
|
43
|
+
default: 'Selection'
|
44
44
|
},
|
45
45
|
placeholder: {
|
46
46
|
type: String,
|
47
|
-
default:
|
47
|
+
default: 'Select an option'
|
48
48
|
},
|
49
49
|
options: {
|
50
50
|
type: Array,
|
@@ -68,11 +68,11 @@ function onSelectChild(child) {
|
|
68
68
|
} else {
|
69
69
|
selectedChildren.value.push(child.id);
|
70
70
|
}
|
71
|
-
emit(
|
71
|
+
emit('update:model-value', selectedChildren.value.length > 0 ? selectedChildren.value : undefined);
|
72
72
|
}
|
73
73
|
function onSelectOption() {
|
74
74
|
selectedChildren.value = [];
|
75
|
-
emit(
|
75
|
+
emit('update:model-value', undefined);
|
76
76
|
}
|
77
77
|
watch(() => props.modelValue, (value) => {
|
78
78
|
selectedOption.value = resolveSelectedOption();
|