@inriver/inri 1.13.0 → 1.15.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.
- package/.changeset/README.md +8 -0
- package/.changeset/config.json +11 -0
- package/.eslintrc.js +5 -5
- package/azure/pipelines/single-build-release.yml +6 -0
- package/azure/pipelines/templates/deployFramework.yml +50 -0
- package/componentProperties.d.ts +8 -8
- package/configs/base-eslint-config.js +36 -36
- package/configs/base-tailwind-config.js +149 -149
- package/i18n.ts +11 -11
- package/index.ts +29 -29
- package/package.json +7 -2
- package/src/components/CAutoBreadcrumbs.vue +72 -72
- package/src/components/CBtn.vue +98 -98
- package/src/components/CColorPicker.vue +55 -55
- package/src/components/CContextMenu.vue +29 -29
- package/src/components/CDatePicker.vue +51 -51
- package/src/components/CDeleteTileBtn.vue +52 -52
- package/src/components/CDialog.vue +253 -253
- package/src/components/CDialogCloseBtn.vue +9 -9
- package/src/components/CDirtyCheck.vue +68 -68
- package/src/components/CDrawer.vue +44 -44
- package/src/components/CDrawerButton.vue +91 -91
- package/src/components/CExpansionItem.vue +57 -57
- package/src/components/CExpansionItemWithCheckbox.vue +41 -41
- package/src/components/CFileDropzone.vue +114 -114
- package/src/components/CGrid.vue +101 -101
- package/src/components/CHeader.vue +10 -10
- package/src/components/CHeaderLinks.vue +61 -61
- package/src/components/CHeaderMenuLink.vue +51 -51
- package/src/components/CHeaderSearch.vue +142 -142
- package/src/components/CIconBtn.vue +70 -70
- package/src/components/CMenuItem.vue +66 -66
- package/src/components/CPageContainer.vue +11 -11
- package/src/components/CPageError.vue +24 -24
- package/src/components/CPageSpinner.vue +18 -18
- package/src/components/CSearch.vue +45 -45
- package/src/components/CSection.vue +29 -29
- package/src/components/CSectionTitle.vue +8 -8
- package/src/components/CSelect.vue +208 -208
- package/src/components/CSlideEffect.vue +62 -62
- package/src/components/CSpinner.vue +107 -107
- package/src/components/CTableActions.vue +16 -16
- package/src/components/CTileBtn.vue +178 -178
- package/src/components/CTimePicker.vue +42 -42
- package/src/components/CToggleGridView.vue +26 -26
- package/src/components/CToggleSidebarBtn.vue +19 -19
- package/src/components/CTooltip.vue +44 -44
- package/src/components/CTreeNode.vue +39 -39
- package/src/components/cards/CBannerCard.vue +103 -103
- package/src/components/cards/CSmallCard.vue +149 -149
- package/src/components/internal-components/ConfirmDialog.vue +78 -78
- package/src/composables/useDialog.ts +46 -46
- package/src/composables/useDirtyCheck.ts +25 -25
- package/src/composables/useDoubleClickListener.ts +28 -28
- package/src/composables/useSelectable.ts +62 -62
- package/src/composables/useTruncateChips.ts +46 -46
- package/src/i18n/de/index.ts +17 -17
- package/src/i18n/en/index.ts +84 -84
- package/src/i18n/es/index.ts +7 -7
- package/src/i18n/fr/index.ts +7 -7
- package/src/init/initInriFramework.ts +37 -37
- package/src/init/useInriApp.ts +55 -55
- package/src/layouts/CLayoutBlank.vue +7 -7
- package/src/layouts/CLayoutWithBackButton.vue +50 -50
- package/src/layouts/CLayoutWithSidebars.vue +46 -46
- package/src/layouts/layout-fragments/CPageAutoBreadcrumbs.vue +6 -6
- package/src/layouts/layout-fragments/CPageBackButton.vue +18 -18
- package/src/layouts/layout-fragments/CPageBlank.vue +20 -20
- package/src/layouts/layout-fragments/CPageFlexCol.vue +5 -5
- package/src/layouts/layout-fragments/CPageLeftSidebar.vue +5 -5
- package/src/layouts/layout-fragments/CPageMainContent.vue +5 -5
- package/src/layouts/layout-fragments/CPageOuterWrapper.vue +5 -5
- package/src/layouts/layout-fragments/CPageRightSidebar.vue +5 -5
- package/src/layouts/layout-fragments/CPageTitle.vue +34 -34
- package/src/plugins/dialog.ts +45 -45
- package/src/plugins/errors/ErrorFactories.ts +59 -59
- package/src/plugins/errors/Errors.ts +156 -156
- package/src/plugins/errors/Exception.ts +6 -6
- package/src/plugins/errors/globalErrorHandler.ts +21 -21
- package/src/plugins/errors/handleError.ts +34 -34
- package/src/plugins/errors/logger.ts +16 -16
- package/src/plugins/errors/vueErrorHandler.ts +26 -26
- package/src/plugins/globalAppConfig.ts +25 -25
- package/src/plugins/i18n.ts +46 -46
- package/src/plugins/inriIcons.ts +58 -58
- package/src/plugins/inriverQuasarComponentConfigurations.ts +67 -67
- package/src/plugins/library.ts +119 -119
- package/src/plugins/notify.ts +153 -153
- package/src/plugins/quasar-user-options.ts +19 -19
- package/src/plugins/validationRules.ts +292 -292
- package/src/shims-vue.d.ts +6 -6
- package/src/stores/inriStore.ts +54 -54
- package/src/stores/interfaceLanguageStore.ts +27 -27
- package/src/styles/_css-variables.scss +101 -101
- package/src/styles/_reset.scss +67 -67
- package/src/styles/_transitions.scss +9 -9
- package/src/styles/_utils.scss +15 -15
- package/src/styles/components/_breadcrumbs.scss +3 -3
- package/src/styles/components/_checkboxes.scss +17 -17
- package/src/styles/components/_chips.scss +17 -17
- package/src/styles/components/_forms.scss +203 -203
- package/src/styles/components/_menu.scss +12 -12
- package/src/styles/components/_notifications.scss +24 -24
- package/src/styles/components/_q-editor.scss +14 -14
- package/src/styles/components/_radio-buttons.scss +17 -17
- package/src/styles/components/_tables.scss +92 -92
- package/src/styles/components/_tooltips.scss +5 -5
- package/src/styles/components/_tree.scss +86 -86
- package/src/styles/components/_truncated-chips.scss +39 -39
- package/src/styles/main.scss +45 -45
- package/src/styles/quasar.variables.scss +50 -50
- package/src/styles/tailwind/index.css +2 -2
- package/src/typings.d.ts +70 -70
- package/src/utils/colorUtils.ts +73 -73
- package/src/utils/errorUtils.ts +37 -37
- package/src/utils/fileUtils.ts +57 -57
- package/src/utils/helpers.ts +6 -6
- package/src/utils/routeUtils.ts +23 -23
- package/tsconfig.json +34 -34
|
@@ -1,45 +1,45 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<q-input
|
|
3
|
-
v-bind="dense ? $inri.inputDense : $inri.input"
|
|
4
|
-
:model-value="modelValue"
|
|
5
|
-
:label="label"
|
|
6
|
-
:placeholder="placeholder"
|
|
7
|
-
@update:model-value="$emit('update:model-value', $event)"
|
|
8
|
-
>
|
|
9
|
-
<template #append>
|
|
10
|
-
<q-icon
|
|
11
|
-
v-if="modelValue?.length"
|
|
12
|
-
name="mdi-close"
|
|
13
|
-
color="grey-darker"
|
|
14
|
-
class="cursor-pointer"
|
|
15
|
-
size="18px"
|
|
16
|
-
@click.stop="$emit('update:model-value', '')"
|
|
17
|
-
/>
|
|
18
|
-
<q-icon
|
|
19
|
-
v-else
|
|
20
|
-
name="inri-search"
|
|
21
|
-
color="grey-dark"
|
|
22
|
-
size="18px"
|
|
23
|
-
/>
|
|
24
|
-
</template>
|
|
25
|
-
</q-input>
|
|
26
|
-
</template>
|
|
27
|
-
|
|
28
|
-
<script setup lang="ts">
|
|
29
|
-
import type { QInputProps } from 'quasar'
|
|
30
|
-
|
|
31
|
-
defineEmits(['update:model-value'])
|
|
32
|
-
|
|
33
|
-
interface Props extends QInputProps {
|
|
34
|
-
modelValue: string,
|
|
35
|
-
label: string,
|
|
36
|
-
placeholder?: string,
|
|
37
|
-
dense?: boolean,
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
withDefaults(defineProps<Props>(), {
|
|
41
|
-
modelValue: undefined,
|
|
42
|
-
label: undefined,
|
|
43
|
-
placeholder: undefined,
|
|
44
|
-
})
|
|
45
|
-
</script>
|
|
1
|
+
<template>
|
|
2
|
+
<q-input
|
|
3
|
+
v-bind="dense ? $inri.inputDense : $inri.input"
|
|
4
|
+
:model-value="modelValue"
|
|
5
|
+
:label="label"
|
|
6
|
+
:placeholder="placeholder"
|
|
7
|
+
@update:model-value="$emit('update:model-value', $event)"
|
|
8
|
+
>
|
|
9
|
+
<template #append>
|
|
10
|
+
<q-icon
|
|
11
|
+
v-if="modelValue?.length"
|
|
12
|
+
name="mdi-close"
|
|
13
|
+
color="grey-darker"
|
|
14
|
+
class="cursor-pointer"
|
|
15
|
+
size="18px"
|
|
16
|
+
@click.stop="$emit('update:model-value', '')"
|
|
17
|
+
/>
|
|
18
|
+
<q-icon
|
|
19
|
+
v-else
|
|
20
|
+
name="inri-search"
|
|
21
|
+
color="grey-dark"
|
|
22
|
+
size="18px"
|
|
23
|
+
/>
|
|
24
|
+
</template>
|
|
25
|
+
</q-input>
|
|
26
|
+
</template>
|
|
27
|
+
|
|
28
|
+
<script setup lang="ts">
|
|
29
|
+
import type { QInputProps } from 'quasar'
|
|
30
|
+
|
|
31
|
+
defineEmits(['update:model-value'])
|
|
32
|
+
|
|
33
|
+
interface Props extends QInputProps {
|
|
34
|
+
modelValue: string,
|
|
35
|
+
label: string,
|
|
36
|
+
placeholder?: string,
|
|
37
|
+
dense?: boolean,
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
withDefaults(defineProps<Props>(), {
|
|
41
|
+
modelValue: undefined,
|
|
42
|
+
label: undefined,
|
|
43
|
+
placeholder: undefined,
|
|
44
|
+
})
|
|
45
|
+
</script>
|
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<section
|
|
3
|
-
class="c-section"
|
|
4
|
-
:class="{
|
|
5
|
-
'overflow-y-overlay': scroll || main,
|
|
6
|
-
'flex-1': flex || main,
|
|
7
|
-
'border-t': borderT,
|
|
8
|
-
'border-b': borderB,
|
|
9
|
-
}"
|
|
10
|
-
>
|
|
11
|
-
<slot />
|
|
12
|
-
</section>
|
|
13
|
-
</template>
|
|
14
|
-
|
|
15
|
-
<script setup lang="ts">
|
|
16
|
-
defineProps({
|
|
17
|
-
scroll: Boolean,
|
|
18
|
-
flex: Boolean,
|
|
19
|
-
main: Boolean,
|
|
20
|
-
borderT: Boolean,
|
|
21
|
-
borderB: Boolean,
|
|
22
|
-
})
|
|
23
|
-
</script>
|
|
24
|
-
|
|
25
|
-
<style>
|
|
26
|
-
.c-section {
|
|
27
|
-
@apply py-7 px-6;
|
|
28
|
-
}
|
|
29
|
-
</style>
|
|
1
|
+
<template>
|
|
2
|
+
<section
|
|
3
|
+
class="c-section"
|
|
4
|
+
:class="{
|
|
5
|
+
'overflow-y-overlay': scroll || main,
|
|
6
|
+
'flex-1': flex || main,
|
|
7
|
+
'border-t': borderT,
|
|
8
|
+
'border-b': borderB,
|
|
9
|
+
}"
|
|
10
|
+
>
|
|
11
|
+
<slot />
|
|
12
|
+
</section>
|
|
13
|
+
</template>
|
|
14
|
+
|
|
15
|
+
<script setup lang="ts">
|
|
16
|
+
defineProps({
|
|
17
|
+
scroll: Boolean,
|
|
18
|
+
flex: Boolean,
|
|
19
|
+
main: Boolean,
|
|
20
|
+
borderT: Boolean,
|
|
21
|
+
borderB: Boolean,
|
|
22
|
+
})
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
<style>
|
|
26
|
+
.c-section {
|
|
27
|
+
@apply py-7 px-6;
|
|
28
|
+
}
|
|
29
|
+
</style>
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div
|
|
3
|
-
class="text-h3 mb-4"
|
|
4
|
-
data-id="section-title"
|
|
5
|
-
>
|
|
6
|
-
<slot />
|
|
7
|
-
</div>
|
|
8
|
-
</template>
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
class="text-h3 mb-4"
|
|
4
|
+
data-id="section-title"
|
|
5
|
+
>
|
|
6
|
+
<slot />
|
|
7
|
+
</div>
|
|
8
|
+
</template>
|
|
@@ -1,208 +1,208 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<q-select
|
|
3
|
-
ref="selectRef"
|
|
4
|
-
class="c-select"
|
|
5
|
-
:model-value="modelValue"
|
|
6
|
-
v-bind="dense ? $inri.inputDense : $inri.input"
|
|
7
|
-
:options="internalOptions"
|
|
8
|
-
:multiple="multiple"
|
|
9
|
-
:use-input="dense || useInput"
|
|
10
|
-
:placeholder="selectedPlaceholder"
|
|
11
|
-
:hide-selected="dense"
|
|
12
|
-
:emit-value="emitValue"
|
|
13
|
-
:option-label="optionLabel"
|
|
14
|
-
:option-value="optionValue"
|
|
15
|
-
clear-icon="mdi-close"
|
|
16
|
-
@blur="clearInputValue"
|
|
17
|
-
@filter="filter"
|
|
18
|
-
@update:model-value="onModelUpdate"
|
|
19
|
-
>
|
|
20
|
-
<template #no-option>
|
|
21
|
-
<q-item>
|
|
22
|
-
<q-item-section>
|
|
23
|
-
{{ $t('inri.select.no_results') }}
|
|
24
|
-
</q-item-section>
|
|
25
|
-
</q-item>
|
|
26
|
-
</template>
|
|
27
|
-
|
|
28
|
-
<!-- select all-->
|
|
29
|
-
<template
|
|
30
|
-
v-if="multiple"
|
|
31
|
-
#before-options
|
|
32
|
-
>
|
|
33
|
-
<q-item>
|
|
34
|
-
<q-item-section>
|
|
35
|
-
<q-checkbox
|
|
36
|
-
:model-value="allSelectedStatus"
|
|
37
|
-
v-bind="$inri.checkbox"
|
|
38
|
-
:label="$t('inri.select.select_all')"
|
|
39
|
-
tabindex="-1"
|
|
40
|
-
@click="onToggleAll"
|
|
41
|
-
/>
|
|
42
|
-
</q-item-section>
|
|
43
|
-
</q-item>
|
|
44
|
-
</template>
|
|
45
|
-
|
|
46
|
-
<!-- list item-->
|
|
47
|
-
<template #option="{ itemProps, opt, selected, toggleOption }">
|
|
48
|
-
<!-- multi -->
|
|
49
|
-
<q-item
|
|
50
|
-
v-if="multiple"
|
|
51
|
-
v-bind="itemProps"
|
|
52
|
-
>
|
|
53
|
-
<q-item-section>
|
|
54
|
-
<q-checkbox
|
|
55
|
-
:model-value="selected"
|
|
56
|
-
v-bind="$inri.checkbox"
|
|
57
|
-
:label="getOptionLabel(opt)"
|
|
58
|
-
tabindex="-1"
|
|
59
|
-
@click="toggleOption(opt)"
|
|
60
|
-
/>
|
|
61
|
-
</q-item-section>
|
|
62
|
-
</q-item>
|
|
63
|
-
|
|
64
|
-
<!-- single -->
|
|
65
|
-
<q-item
|
|
66
|
-
v-else
|
|
67
|
-
v-bind="itemProps"
|
|
68
|
-
>
|
|
69
|
-
<q-item-section>
|
|
70
|
-
{{ getOptionLabel(opt) }}
|
|
71
|
-
</q-item-section>
|
|
72
|
-
</q-item>
|
|
73
|
-
</template>
|
|
74
|
-
</q-select>
|
|
75
|
-
</template>
|
|
76
|
-
|
|
77
|
-
<script setup lang="ts">
|
|
78
|
-
import { computed, ref, toRef, useAttrs } from 'vue'
|
|
79
|
-
import { QSelect } from 'quasar'
|
|
80
|
-
import useSelectable from '../composables/useSelectable'
|
|
81
|
-
|
|
82
|
-
const emit = defineEmits(['update:modelValue'])
|
|
83
|
-
const attrs = useAttrs()
|
|
84
|
-
|
|
85
|
-
defineExpose({
|
|
86
|
-
clearInputValue,
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
const props = defineProps({
|
|
90
|
-
modelValue: {
|
|
91
|
-
type: [Object, String, Number, Boolean, Array],
|
|
92
|
-
default: undefined,
|
|
93
|
-
},
|
|
94
|
-
options: {
|
|
95
|
-
type: Array,
|
|
96
|
-
default: () => [],
|
|
97
|
-
},
|
|
98
|
-
multiple: Boolean,
|
|
99
|
-
dense: Boolean,
|
|
100
|
-
useInput: Boolean,
|
|
101
|
-
emitValue: Boolean,
|
|
102
|
-
optionLabel: {
|
|
103
|
-
type: String,
|
|
104
|
-
default: 'label',
|
|
105
|
-
},
|
|
106
|
-
optionValue: {
|
|
107
|
-
type: String,
|
|
108
|
-
default: 'value',
|
|
109
|
-
},
|
|
110
|
-
placeholder: {
|
|
111
|
-
type: String,
|
|
112
|
-
default: undefined,
|
|
113
|
-
},
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
// State etc.
|
|
117
|
-
const internalOptions = ref(props.options)
|
|
118
|
-
const selectRef = ref<QSelect>()
|
|
119
|
-
const { allSelectedStatus, toggleAllItemsWithEmit } = useSelectable(toRef(props, 'options'), toRef(props, 'modelValue'))
|
|
120
|
-
|
|
121
|
-
const selectedPlaceholder = computed(() => {
|
|
122
|
-
if (props.dense) {
|
|
123
|
-
const placeholder = props.placeholder || ''
|
|
124
|
-
|
|
125
|
-
if (!props.multiple) {
|
|
126
|
-
return props.modelValue ? getOptionLabel(props.modelValue) : placeholder
|
|
127
|
-
} else {
|
|
128
|
-
return Array.isArray(props.modelValue) && props.modelValue?.length ? `${placeholder} (${props.modelValue.length})` : placeholder
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
return props.placeholder
|
|
133
|
-
})
|
|
134
|
-
|
|
135
|
-
function getOptionLabel (opt) {
|
|
136
|
-
return opt[props.optionLabel] || opt
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
function filter (val, update) {
|
|
140
|
-
update(
|
|
141
|
-
() => {
|
|
142
|
-
const lowerCaseValue = val?.toLowerCase()
|
|
143
|
-
internalOptions.value = props.options.filter(option => getOptionLabel(option).toLowerCase().indexOf(lowerCaseValue) > -1)
|
|
144
|
-
},
|
|
145
|
-
|
|
146
|
-
// "ref" is the Vue reference to the QSelect
|
|
147
|
-
ref => {
|
|
148
|
-
if (val !== '' && ref.options.length > 0) {
|
|
149
|
-
// Reset optionIndex in case there is something selected
|
|
150
|
-
ref.setOptionIndex(-1)
|
|
151
|
-
|
|
152
|
-
// If it is possible to add new values then only try to focus on an exact match.
|
|
153
|
-
// If we can't add new values then always focus on the first item.
|
|
154
|
-
if (attrs.onNewValue) {
|
|
155
|
-
// Try to find a matched item.
|
|
156
|
-
const lowerCaseValue = val?.toLowerCase()
|
|
157
|
-
const optionsIndex = ref.options.findIndex(option => getOptionLabel(option).toLowerCase() === lowerCaseValue)
|
|
158
|
-
|
|
159
|
-
// If there is no exact match (casing excluded) then don't set focus.
|
|
160
|
-
// This is to allow adding new items, or it'll just toggle the focused item which can make it impossible to add new values.
|
|
161
|
-
if (optionsIndex > -1) {
|
|
162
|
-
// The q-select options starts at index 1.
|
|
163
|
-
ref.moveOptionSelection(optionsIndex + 1, true)
|
|
164
|
-
}
|
|
165
|
-
} else {
|
|
166
|
-
// The q-select options starts at index 1.
|
|
167
|
-
ref.moveOptionSelection(1, true)
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
},
|
|
171
|
-
)
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
function clearInputValue () {
|
|
175
|
-
if (selectRef.value) {
|
|
176
|
-
selectRef.value.updateInputValue('', true)
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
function onModelUpdate (val) {
|
|
181
|
-
emit('update:modelValue', val)
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
function onToggleAll (evt, emitString) {
|
|
185
|
-
if (selectRef.value) {
|
|
186
|
-
selectRef.value.hidePopup()
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
toggleAllItemsWithEmit(evt, emitString)
|
|
190
|
-
}
|
|
191
|
-
</script>
|
|
192
|
-
|
|
193
|
-
<style lang="scss">
|
|
194
|
-
.c-select {
|
|
195
|
-
::placeholder {
|
|
196
|
-
color: var(--color-text);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// Prevent the 'input' text from being selected when navigating the list of options
|
|
200
|
-
::selection {
|
|
201
|
-
background: none;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
::-moz-selection {
|
|
205
|
-
background: none;
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
</style>
|
|
1
|
+
<template>
|
|
2
|
+
<q-select
|
|
3
|
+
ref="selectRef"
|
|
4
|
+
class="c-select"
|
|
5
|
+
:model-value="modelValue"
|
|
6
|
+
v-bind="dense ? $inri.inputDense : $inri.input"
|
|
7
|
+
:options="internalOptions"
|
|
8
|
+
:multiple="multiple"
|
|
9
|
+
:use-input="dense || useInput"
|
|
10
|
+
:placeholder="selectedPlaceholder"
|
|
11
|
+
:hide-selected="dense"
|
|
12
|
+
:emit-value="emitValue"
|
|
13
|
+
:option-label="optionLabel"
|
|
14
|
+
:option-value="optionValue"
|
|
15
|
+
clear-icon="mdi-close"
|
|
16
|
+
@blur="clearInputValue"
|
|
17
|
+
@filter="filter"
|
|
18
|
+
@update:model-value="onModelUpdate"
|
|
19
|
+
>
|
|
20
|
+
<template #no-option>
|
|
21
|
+
<q-item>
|
|
22
|
+
<q-item-section>
|
|
23
|
+
{{ $t('inri.select.no_results') }}
|
|
24
|
+
</q-item-section>
|
|
25
|
+
</q-item>
|
|
26
|
+
</template>
|
|
27
|
+
|
|
28
|
+
<!-- select all-->
|
|
29
|
+
<template
|
|
30
|
+
v-if="multiple"
|
|
31
|
+
#before-options
|
|
32
|
+
>
|
|
33
|
+
<q-item>
|
|
34
|
+
<q-item-section>
|
|
35
|
+
<q-checkbox
|
|
36
|
+
:model-value="allSelectedStatus"
|
|
37
|
+
v-bind="$inri.checkbox"
|
|
38
|
+
:label="$t('inri.select.select_all')"
|
|
39
|
+
tabindex="-1"
|
|
40
|
+
@click="onToggleAll"
|
|
41
|
+
/>
|
|
42
|
+
</q-item-section>
|
|
43
|
+
</q-item>
|
|
44
|
+
</template>
|
|
45
|
+
|
|
46
|
+
<!-- list item-->
|
|
47
|
+
<template #option="{ itemProps, opt, selected, toggleOption }">
|
|
48
|
+
<!-- multi -->
|
|
49
|
+
<q-item
|
|
50
|
+
v-if="multiple"
|
|
51
|
+
v-bind="itemProps"
|
|
52
|
+
>
|
|
53
|
+
<q-item-section>
|
|
54
|
+
<q-checkbox
|
|
55
|
+
:model-value="selected"
|
|
56
|
+
v-bind="$inri.checkbox"
|
|
57
|
+
:label="getOptionLabel(opt)"
|
|
58
|
+
tabindex="-1"
|
|
59
|
+
@click="toggleOption(opt)"
|
|
60
|
+
/>
|
|
61
|
+
</q-item-section>
|
|
62
|
+
</q-item>
|
|
63
|
+
|
|
64
|
+
<!-- single -->
|
|
65
|
+
<q-item
|
|
66
|
+
v-else
|
|
67
|
+
v-bind="itemProps"
|
|
68
|
+
>
|
|
69
|
+
<q-item-section>
|
|
70
|
+
{{ getOptionLabel(opt) }}
|
|
71
|
+
</q-item-section>
|
|
72
|
+
</q-item>
|
|
73
|
+
</template>
|
|
74
|
+
</q-select>
|
|
75
|
+
</template>
|
|
76
|
+
|
|
77
|
+
<script setup lang="ts">
|
|
78
|
+
import { computed, ref, toRef, useAttrs } from 'vue'
|
|
79
|
+
import { QSelect } from 'quasar'
|
|
80
|
+
import useSelectable from '../composables/useSelectable'
|
|
81
|
+
|
|
82
|
+
const emit = defineEmits(['update:modelValue'])
|
|
83
|
+
const attrs = useAttrs()
|
|
84
|
+
|
|
85
|
+
defineExpose({
|
|
86
|
+
clearInputValue,
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
const props = defineProps({
|
|
90
|
+
modelValue: {
|
|
91
|
+
type: [Object, String, Number, Boolean, Array],
|
|
92
|
+
default: undefined,
|
|
93
|
+
},
|
|
94
|
+
options: {
|
|
95
|
+
type: Array,
|
|
96
|
+
default: () => [],
|
|
97
|
+
},
|
|
98
|
+
multiple: Boolean,
|
|
99
|
+
dense: Boolean,
|
|
100
|
+
useInput: Boolean,
|
|
101
|
+
emitValue: Boolean,
|
|
102
|
+
optionLabel: {
|
|
103
|
+
type: String,
|
|
104
|
+
default: 'label',
|
|
105
|
+
},
|
|
106
|
+
optionValue: {
|
|
107
|
+
type: String,
|
|
108
|
+
default: 'value',
|
|
109
|
+
},
|
|
110
|
+
placeholder: {
|
|
111
|
+
type: String,
|
|
112
|
+
default: undefined,
|
|
113
|
+
},
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
// State etc.
|
|
117
|
+
const internalOptions = ref(props.options)
|
|
118
|
+
const selectRef = ref<QSelect>()
|
|
119
|
+
const { allSelectedStatus, toggleAllItemsWithEmit } = useSelectable(toRef(props, 'options'), toRef(props, 'modelValue'))
|
|
120
|
+
|
|
121
|
+
const selectedPlaceholder = computed(() => {
|
|
122
|
+
if (props.dense) {
|
|
123
|
+
const placeholder = props.placeholder || ''
|
|
124
|
+
|
|
125
|
+
if (!props.multiple) {
|
|
126
|
+
return props.modelValue ? getOptionLabel(props.modelValue) : placeholder
|
|
127
|
+
} else {
|
|
128
|
+
return Array.isArray(props.modelValue) && props.modelValue?.length ? `${placeholder} (${props.modelValue.length})` : placeholder
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return props.placeholder
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
function getOptionLabel (opt) {
|
|
136
|
+
return opt[props.optionLabel] || opt
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function filter (val, update) {
|
|
140
|
+
update(
|
|
141
|
+
() => {
|
|
142
|
+
const lowerCaseValue = val?.toLowerCase()
|
|
143
|
+
internalOptions.value = props.options.filter(option => getOptionLabel(option).toLowerCase().indexOf(lowerCaseValue) > -1)
|
|
144
|
+
},
|
|
145
|
+
|
|
146
|
+
// "ref" is the Vue reference to the QSelect
|
|
147
|
+
ref => {
|
|
148
|
+
if (val !== '' && ref.options.length > 0) {
|
|
149
|
+
// Reset optionIndex in case there is something selected
|
|
150
|
+
ref.setOptionIndex(-1)
|
|
151
|
+
|
|
152
|
+
// If it is possible to add new values then only try to focus on an exact match.
|
|
153
|
+
// If we can't add new values then always focus on the first item.
|
|
154
|
+
if (attrs.onNewValue) {
|
|
155
|
+
// Try to find a matched item.
|
|
156
|
+
const lowerCaseValue = val?.toLowerCase()
|
|
157
|
+
const optionsIndex = ref.options.findIndex(option => getOptionLabel(option).toLowerCase() === lowerCaseValue)
|
|
158
|
+
|
|
159
|
+
// If there is no exact match (casing excluded) then don't set focus.
|
|
160
|
+
// This is to allow adding new items, or it'll just toggle the focused item which can make it impossible to add new values.
|
|
161
|
+
if (optionsIndex > -1) {
|
|
162
|
+
// The q-select options starts at index 1.
|
|
163
|
+
ref.moveOptionSelection(optionsIndex + 1, true)
|
|
164
|
+
}
|
|
165
|
+
} else {
|
|
166
|
+
// The q-select options starts at index 1.
|
|
167
|
+
ref.moveOptionSelection(1, true)
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function clearInputValue () {
|
|
175
|
+
if (selectRef.value) {
|
|
176
|
+
selectRef.value.updateInputValue('', true)
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function onModelUpdate (val) {
|
|
181
|
+
emit('update:modelValue', val)
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function onToggleAll (evt, emitString) {
|
|
185
|
+
if (selectRef.value) {
|
|
186
|
+
selectRef.value.hidePopup()
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
toggleAllItemsWithEmit(evt, emitString)
|
|
190
|
+
}
|
|
191
|
+
</script>
|
|
192
|
+
|
|
193
|
+
<style lang="scss">
|
|
194
|
+
.c-select {
|
|
195
|
+
::placeholder {
|
|
196
|
+
color: var(--color-text);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Prevent the 'input' text from being selected when navigating the list of options
|
|
200
|
+
::selection {
|
|
201
|
+
background: none;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
::-moz-selection {
|
|
205
|
+
background: none;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
</style>
|