adminforth 2.4.0-next.31 → 2.4.0-next.310
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/commands/callTsProxy.js +14 -4
- package/commands/createApp/templates/api.ts.hbs +10 -0
- package/commands/createApp/templates/custom/tsconfig.json.hbs +2 -3
- package/commands/createApp/templates/index.ts.hbs +12 -1
- package/commands/createApp/templates/package.json.hbs +1 -1
- package/commands/createApp/templates/prisma.config.ts.hbs +8 -0
- package/commands/createApp/templates/schema.prisma.hbs +0 -1
- package/commands/createApp/utils.js +10 -0
- package/commands/createCustomComponent/configLoader.js +17 -4
- package/commands/createCustomComponent/main.js +13 -7
- package/commands/createCustomComponent/templates/customCrud/beforeActionButtons.vue.hbs +38 -0
- package/commands/createCustomComponent/templates/customCrud/saveButton.vue.hbs +28 -0
- package/commands/createPlugin/templates/custom/tsconfig.json.hbs +2 -5
- package/commands/createPlugin/templates/package.json.hbs +1 -1
- package/commands/generateModels.js +30 -22
- package/dist/auth.d.ts +9 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +21 -2
- package/dist/auth.js.map +1 -1
- package/dist/dataConnectors/baseConnector.d.ts +1 -1
- package/dist/dataConnectors/baseConnector.d.ts.map +1 -1
- package/dist/dataConnectors/baseConnector.js +69 -17
- package/dist/dataConnectors/baseConnector.js.map +1 -1
- package/dist/dataConnectors/clickhouse.d.ts.map +1 -1
- package/dist/dataConnectors/clickhouse.js +15 -0
- package/dist/dataConnectors/clickhouse.js.map +1 -1
- package/dist/dataConnectors/mongo.d.ts.map +1 -1
- package/dist/dataConnectors/mongo.js +50 -15
- package/dist/dataConnectors/mongo.js.map +1 -1
- package/dist/dataConnectors/mysql.d.ts.map +1 -1
- package/dist/dataConnectors/mysql.js +11 -0
- package/dist/dataConnectors/mysql.js.map +1 -1
- package/dist/dataConnectors/postgres.d.ts.map +1 -1
- package/dist/dataConnectors/postgres.js +43 -14
- package/dist/dataConnectors/postgres.js.map +1 -1
- package/dist/dataConnectors/sqlite.d.ts.map +1 -1
- package/dist/dataConnectors/sqlite.js +11 -0
- package/dist/dataConnectors/sqlite.js.map +1 -1
- package/dist/index.d.ts +12 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +45 -22
- package/dist/index.js.map +1 -1
- package/dist/modules/codeInjector.d.ts +2 -0
- package/dist/modules/codeInjector.d.ts.map +1 -1
- package/dist/modules/codeInjector.js +62 -6
- package/dist/modules/codeInjector.js.map +1 -1
- package/dist/modules/configValidator.d.ts +6 -0
- package/dist/modules/configValidator.d.ts.map +1 -1
- package/dist/modules/configValidator.js +202 -25
- package/dist/modules/configValidator.js.map +1 -1
- package/dist/modules/restApi.d.ts +1 -1
- package/dist/modules/restApi.d.ts.map +1 -1
- package/dist/modules/restApi.js +172 -31
- package/dist/modules/restApi.js.map +1 -1
- package/dist/modules/styles.d.ts +499 -13
- package/dist/modules/styles.d.ts.map +1 -1
- package/dist/modules/styles.js +555 -31
- package/dist/modules/styles.js.map +1 -1
- package/dist/modules/utils.d.ts +7 -15
- package/dist/modules/utils.d.ts.map +1 -1
- package/dist/modules/utils.js +45 -68
- package/dist/modules/utils.js.map +1 -1
- package/dist/servers/express.d.ts +5 -0
- package/dist/servers/express.d.ts.map +1 -1
- package/dist/servers/express.js +40 -1
- package/dist/servers/express.js.map +1 -1
- package/dist/spa/index.html +1 -1
- package/dist/spa/package-lock.json +1208 -708
- package/dist/spa/package.json +34 -34
- package/dist/spa/src/App.vue +59 -174
- package/dist/spa/src/adminforth.ts +42 -18
- package/dist/spa/src/afcl/AreaChart.vue +0 -1
- package/dist/spa/src/afcl/BarChart.vue +2 -2
- package/dist/spa/src/afcl/Button.vue +6 -6
- package/dist/spa/src/afcl/ButtonGroup.vue +91 -0
- package/dist/spa/src/afcl/Card.vue +25 -0
- package/dist/spa/src/afcl/Checkbox.vue +21 -13
- package/dist/spa/src/afcl/CountryFlag.vue +4 -1
- package/dist/spa/src/{components/CustomDatePicker.vue → afcl/DatePicker.vue} +95 -9
- package/dist/spa/src/afcl/Dialog.vue +47 -27
- package/dist/spa/src/afcl/Dropzone.vue +127 -48
- package/dist/spa/src/afcl/Input.vue +14 -6
- package/dist/spa/src/afcl/JsonViewer.vue +25 -0
- package/dist/spa/src/afcl/LinkButton.vue +3 -3
- package/dist/spa/src/afcl/PieChart.vue +5 -5
- package/dist/spa/src/afcl/ProgressBar.vue +7 -7
- package/dist/spa/src/afcl/Select.vue +82 -34
- package/dist/spa/src/afcl/Skeleton.vue +6 -6
- package/dist/spa/src/afcl/Table.vue +315 -73
- package/dist/spa/src/afcl/Textarea.vue +31 -0
- package/dist/spa/src/afcl/Toggle.vue +32 -0
- package/dist/spa/src/afcl/Tooltip.vue +28 -18
- package/dist/spa/src/afcl/VerticalTabs.vue +16 -7
- package/dist/spa/src/afcl/index.ts +6 -3
- package/dist/spa/src/components/AcceptModal.vue +48 -14
- package/dist/spa/src/components/Breadcrumbs.vue +5 -5
- package/dist/spa/src/components/CallActionWrapper.vue +15 -0
- package/dist/spa/src/components/ColumnValueInput.vue +38 -18
- package/dist/spa/src/components/ColumnValueInputWrapper.vue +4 -3
- package/dist/spa/src/components/CustomDateRangePicker.vue +9 -8
- package/dist/spa/src/components/CustomRangePicker.vue +37 -21
- package/dist/spa/src/components/ErrorMessage.vue +21 -0
- package/dist/spa/src/components/Filters.vue +195 -132
- package/dist/spa/src/components/GroupsTable.vue +9 -8
- package/dist/spa/src/components/MenuLink.vue +90 -23
- package/dist/spa/src/components/ResourceForm.vue +94 -51
- package/dist/spa/src/components/ResourceListTable.vue +115 -85
- package/dist/spa/src/components/ResourceListTableVirtual.vue +114 -80
- package/dist/spa/src/components/ShowTable.vue +21 -15
- package/dist/spa/src/components/Sidebar.vue +470 -0
- package/dist/spa/src/components/SingleSkeletLoader.vue +6 -6
- package/dist/spa/src/components/SkeleteLoader.vue +3 -3
- package/dist/spa/src/components/ThreeDotsMenu.vue +84 -15
- package/dist/spa/src/components/Toast.vue +40 -29
- package/dist/spa/src/components/UserMenuSettingsButton.vue +69 -0
- package/dist/spa/src/components/ValueRenderer.vue +44 -17
- package/dist/spa/src/controls/BoolToggle.vue +34 -0
- package/dist/spa/src/i18n.ts +5 -3
- package/dist/spa/src/main.ts +1 -1
- package/dist/spa/src/renderers/CompactField.vue +1 -1
- package/dist/spa/src/renderers/CompactUUID.vue +1 -1
- package/dist/spa/src/router/index.ts +8 -0
- package/dist/spa/src/shims-vue.d.ts +5 -0
- package/dist/spa/src/spa_types/core.ts +13 -1
- package/dist/spa/src/stores/core.ts +13 -1
- package/dist/spa/src/stores/filters.ts +33 -2
- package/dist/spa/src/stores/modal.ts +6 -1
- package/dist/spa/src/stores/toast.ts +22 -3
- package/dist/spa/src/types/Back.ts +163 -23
- package/dist/spa/src/types/Common.ts +91 -32
- package/dist/spa/src/types/FrontendAPI.ts +31 -5
- package/dist/spa/src/types/adapters/CaptchaAdapter.ts +34 -0
- package/dist/spa/src/types/adapters/EmailAdapter.ts +2 -2
- package/dist/spa/src/types/adapters/ImageVisionAdapter.ts +30 -0
- package/dist/spa/src/types/adapters/KeyValueAdapter.ts +16 -0
- package/dist/spa/src/types/adapters/index.ts +8 -0
- package/dist/spa/src/utils.ts +291 -11
- package/dist/spa/src/views/CreateView.vue +63 -21
- package/dist/spa/src/views/EditView.vue +55 -22
- package/dist/spa/src/views/ListView.vue +144 -87
- package/dist/spa/src/views/LoginView.vue +26 -35
- package/dist/spa/src/views/ResourceParent.vue +2 -2
- package/dist/spa/src/views/SettingsView.vue +121 -0
- package/dist/spa/src/views/ShowView.vue +83 -53
- package/dist/spa/src/websocket.ts +6 -1
- package/dist/spa/tsconfig.app.json +1 -1
- package/dist/spa/vite.config.ts +45 -2
- package/dist/types/Back.d.ts +146 -14
- package/dist/types/Back.d.ts.map +1 -1
- package/dist/types/Back.js +15 -0
- package/dist/types/Back.js.map +1 -1
- package/dist/types/Common.d.ts +106 -29
- package/dist/types/Common.d.ts.map +1 -1
- package/dist/types/Common.js.map +1 -1
- package/dist/types/FrontendAPI.d.ts +31 -3
- package/dist/types/FrontendAPI.d.ts.map +1 -1
- package/dist/types/FrontendAPI.js.map +1 -1
- package/dist/types/adapters/CaptchaAdapter.d.ts +30 -0
- package/dist/types/adapters/CaptchaAdapter.d.ts.map +1 -0
- package/dist/types/adapters/CaptchaAdapter.js +5 -0
- package/dist/types/adapters/CaptchaAdapter.js.map +1 -0
- package/dist/types/adapters/EmailAdapter.d.ts +1 -1
- package/dist/types/adapters/ImageVisionAdapter.d.ts +25 -0
- package/dist/types/adapters/ImageVisionAdapter.d.ts.map +1 -0
- package/dist/types/adapters/ImageVisionAdapter.js +2 -0
- package/dist/types/adapters/ImageVisionAdapter.js.map +1 -0
- package/dist/types/adapters/KeyValueAdapter.d.ts +10 -0
- package/dist/types/adapters/KeyValueAdapter.d.ts.map +1 -0
- package/dist/types/adapters/KeyValueAdapter.js +2 -0
- package/dist/types/adapters/KeyValueAdapter.js.map +1 -0
- package/dist/types/adapters/index.d.ts +9 -0
- package/dist/types/adapters/index.d.ts.map +1 -0
- package/dist/types/adapters/index.js +2 -0
- package/dist/types/adapters/index.js.map +1 -0
- package/package.json +4 -2
- package/dist/spa/src/types/adapters/index.js +0 -5
|
@@ -1,55 +1,58 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="afcl-select-wrapper relative inline-block" ref="internalSelect"
|
|
2
|
+
<div class="afcl-select afcl-select-wrapper relative inline-block" ref="internalSelect"
|
|
3
3
|
:class="{'opacity-50': readonly}"
|
|
4
4
|
>
|
|
5
5
|
<div class="relative">
|
|
6
6
|
<input
|
|
7
7
|
ref="inputEl"
|
|
8
8
|
type="text"
|
|
9
|
-
:readonly="readonly"
|
|
9
|
+
:readonly="readonly || searchDisabled"
|
|
10
10
|
v-model="search"
|
|
11
11
|
@click="inputClick"
|
|
12
12
|
@input="inputInput"
|
|
13
|
-
class="
|
|
13
|
+
class="block w-full pl-3 pr-10 py-2.5 border border-lightDropownButtonsBorder rounded-md leading-5 bg-lightDropdownButtonsBackground
|
|
14
|
+
placeholder-lightDropdownButtonsPlaceholderText text-lightDropdownButtonsText sm:text-sm transition duration-150 ease-in-out dark:bg-darkDropdownButtonsBackground dark:border-darkDropdownButtonsBorder dark:placeholder-darkDropdownButtonsPlaceholderText
|
|
15
|
+
dark:text-darkDropdownButtonsText focus:ring-lightPrimary focus:border-lightPrimary dark:focus:ring-darkPrimary dark:focus:border-darkPrimary"
|
|
14
16
|
autocomplete="off" data-custom="no-autofill"
|
|
15
17
|
:placeholder="
|
|
16
18
|
selectedItems.length && !multiple ? '' : (showDropdown ? $t('Search') : placeholder || $t('Select...'))
|
|
17
19
|
"
|
|
18
20
|
/>
|
|
19
21
|
|
|
20
|
-
<div v-if="!multiple && selectedItems.length" class="absolute pointer-events-none inset-y-0 left-2 flex items-center pr-2 px-1">
|
|
22
|
+
<div v-if="!multiple && selectedItems.length" class="text-lightDropdownButtonsText dark:text-darkDropdownButtonsText absolute pointer-events-none inset-y-0 left-2 flex items-center pr-2 px-1">
|
|
21
23
|
<slot
|
|
22
24
|
name="selected-item"
|
|
23
25
|
:option="selectedItems[0]"
|
|
24
26
|
></slot>
|
|
25
|
-
<span v-if="!$slots['selected-item']" class="text-
|
|
27
|
+
<span v-if="!$slots['selected-item']" class="text-lightDropdownButtonsText dark:text-darkDropdownButtonsText font-medium ">
|
|
26
28
|
{{ selectedItems[0]?.label }}
|
|
27
29
|
</span>
|
|
28
30
|
</div>
|
|
29
31
|
|
|
30
32
|
<div class="absolute inset-y-0 right-2 flex items-center pointer-events-none">
|
|
31
33
|
<!-- triangle icon -->
|
|
32
|
-
<IconCaretDownSolid class="h-5 w-5 text-lightPrimary dark:text-
|
|
34
|
+
<IconCaretDownSolid class="h-5 w-5 text-lightPrimary dark:text-darkPrimary opacity-50 transition duration-150 ease-in"
|
|
33
35
|
:class="{ 'transform rotate-180': showDropdown }"
|
|
34
36
|
/>
|
|
35
37
|
</div>
|
|
36
38
|
</div>
|
|
37
|
-
<teleport to="body" v-if="teleportToBody && showDropdown">
|
|
38
|
-
<div ref="dropdownEl" :style="getDropdownPosition" :class="{'shadow-none': isTop}"
|
|
39
|
-
class="fixed
|
|
40
|
-
dark:border-gray-600 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm max-h-48"
|
|
39
|
+
<teleport to="body" v-if="(teleportToBody || teleportToTop) && showDropdown">
|
|
40
|
+
<div ref="dropdownEl" :style="getDropdownPosition" :class="{'shadow-none': isTop, 'z-10': teleportToBody, 'z-[1000]': teleportToTop}"
|
|
41
|
+
class="fixed w-full bg-lightDropdownOptionsBackground shadow-lg dark:shadow-black dark:bg-darkDropdownOptionsBackground
|
|
42
|
+
dark:border-gray-600 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm max-h-48"
|
|
43
|
+
@scroll="handleDropdownScroll">
|
|
41
44
|
<div
|
|
42
45
|
v-for="item in filteredItems"
|
|
43
46
|
:key="item.value"
|
|
44
|
-
class="px-4 py-2 cursor-pointer hover:bg-
|
|
45
|
-
:class="{ 'bg-
|
|
47
|
+
class="px-4 py-2 cursor-pointer hover:bg-lightDropdownOptionsHoverBackground dark:hover:bg-darkDropdownOptionsHoverBackground text-lightDropdownOptionsText dark:text-darkDropdownOptionsText"
|
|
48
|
+
:class="{ 'bg-lightDropdownPicked dark:bg-darkDropdownPicked': selectedItems.includes(item) }"
|
|
46
49
|
@click="toogleItem(item)"
|
|
47
50
|
>
|
|
48
51
|
<slot name="item" :option="item"></slot>
|
|
49
52
|
<label v-if="!$slots.item" :for="item.value">{{ item.label }}</label>
|
|
50
53
|
</div>
|
|
51
|
-
<div v-if="!filteredItems.length" class="px-4 py-2 cursor-pointer text-
|
|
52
|
-
{{
|
|
54
|
+
<div v-if="!filteredItems.length" class="px-4 py-2 cursor-pointer text-lightDropdownOptionsText dark:text-darkDropdownOptionsText">
|
|
55
|
+
{{ $t('No results found') }}
|
|
53
56
|
</div>
|
|
54
57
|
|
|
55
58
|
<div v-if="$slots['extra-item']" class="px-4 py-2 dark:text-gray-400">
|
|
@@ -58,24 +61,24 @@
|
|
|
58
61
|
</div>
|
|
59
62
|
</teleport>
|
|
60
63
|
|
|
61
|
-
<div v-if="!teleportToBody && showDropdown" ref="dropdownEl" :style="dropdownStyle" :class="{'shadow-none': isTop}"
|
|
62
|
-
class="absolute z-10 mt-1 w-full bg-
|
|
63
|
-
dark:border-gray-600 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm max-h-48"
|
|
64
|
+
<div v-if="!teleportToBody && !teleportToTop && showDropdown" ref="dropdownEl" :style="dropdownStyle" :class="{'shadow-none': isTop}"
|
|
65
|
+
class="absolute z-10 mt-1 w-full bg-lightDropdownOptionsBackground shadow-lg text-lightDropdownButtonsText dark:shadow-black dark:bg-darkDropdownOptionsBackground
|
|
66
|
+
dark:border-gray-600 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm max-h-48"
|
|
67
|
+
@scroll="handleDropdownScroll">
|
|
64
68
|
<div
|
|
65
69
|
v-for="item in filteredItems"
|
|
66
70
|
:key="item.value"
|
|
67
|
-
class="px-4 py-2 cursor-pointer hover:bg-
|
|
68
|
-
:class="{ 'bg-
|
|
71
|
+
class="px-4 py-2 cursor-pointer text-lightDropdownOptionsText hover:bg-lightDropdownOptionsHoverBackground dark:hover:bg-darkDropdownOptionsHoverBackground dark:text-darkDropdownOptionsText"
|
|
72
|
+
:class="{ 'bg-lightDropdownPicked dark:bg-darkDropdownPicked': selectedItems.includes(item) }"
|
|
69
73
|
@click="toogleItem(item)"
|
|
70
74
|
>
|
|
71
75
|
<slot name="item" :option="item"></slot>
|
|
72
76
|
<label v-if="!$slots.item" :for="item.value">{{ item.label }}</label>
|
|
73
77
|
</div>
|
|
74
|
-
<div v-if="!filteredItems.length" class="px-4 py-2 cursor-pointer text-
|
|
75
|
-
{{ options
|
|
78
|
+
<div v-if="!filteredItems.length" class="px-4 py-2 cursor-pointer text-lightDropdownOptionsText dark:text-darkDropdownOptionsText">
|
|
79
|
+
{{ options?.length ? $t('No results found') : $t('No items here') }}
|
|
76
80
|
</div>
|
|
77
|
-
|
|
78
|
-
<div v-if="$slots['extra-item']" class="px-4 py-2 dark:text-gray-400">
|
|
81
|
+
<div v-if="$slots['extra-item']" class="px-4 py-2 dark:text-darkDropdownOptionsText">
|
|
79
82
|
<slot name="extra-item"></slot>
|
|
80
83
|
</div>
|
|
81
84
|
|
|
@@ -87,12 +90,12 @@
|
|
|
87
90
|
<template v-for="item in selectedItems" :key="`afcl-select-${item.value}`">
|
|
88
91
|
<slot name="selected-item" :item="item"></slot>
|
|
89
92
|
<div v-if="!$slots['selected-item']"
|
|
90
|
-
class="bg-
|
|
93
|
+
class="bg-lightDropdownMultipleSelectBackground text-lightDropdownMultipleSelectText text-xs font-medium me-2 px-2.5 py-0.5 rounded dark:bg-darkDropdownMultipleSelectBackground dark:text-darkDropdownMultipleSelectText">
|
|
91
94
|
<span>{{ item.label }}</span>
|
|
92
95
|
<button
|
|
93
96
|
type="button"
|
|
94
97
|
@click="toogleItem(item)"
|
|
95
|
-
class="z-index-100 flex-shrink-0 ml-1 h-4 w-4 -mr-1 rounded-full inline-flex items-center justify-center text-
|
|
98
|
+
class="z-index-100 flex-shrink-0 ml-1 h-4 w-4 -mr-1 rounded-full inline-flex items-center justify-center text-lightDropdownMultipleSelectIcon hover:text-lightDropdownMultipleSelectIconHover dark:text-darkDropdownMultipleSelectIcon dark:hover:text-darkDropdownMultipleSelectIconHover focus:outline-none focus:text-lightDropdownMultipleSelectIconFocus focus:bg-lightDropdownMultipleSelectIconFocusBackground dark:focus:text-darkDropdownMultipleSelectIconFocus dark:focus:bg-darkDropdownMultipleSelectIconFocusBackground"
|
|
96
99
|
>
|
|
97
100
|
<span class="sr-only">{{ $t('Remove item') }}</span>
|
|
98
101
|
<svg class="h-2 w-2" stroke="currentColor" fill="none" viewBox="0 0 8 8">
|
|
@@ -111,14 +114,15 @@
|
|
|
111
114
|
</template>
|
|
112
115
|
|
|
113
116
|
<script setup lang="ts">
|
|
114
|
-
import { ref, computed, onMounted, onUnmounted, watch, type Ref } from 'vue';
|
|
117
|
+
import { ref, computed, onMounted, onUnmounted, watch, nextTick,type PropType, type Ref } from 'vue';
|
|
115
118
|
import { IconCaretDownSolid } from '@iconify-prerendered/vue-flowbite';
|
|
116
119
|
import { useElementSize } from '@vueuse/core'
|
|
117
120
|
|
|
118
121
|
const props = defineProps({
|
|
119
122
|
options: Array,
|
|
120
123
|
modelValue: {
|
|
121
|
-
|
|
124
|
+
type: Array as PropType<(string | number)[]>,
|
|
125
|
+
default: () => [],
|
|
122
126
|
},
|
|
123
127
|
multiple: {
|
|
124
128
|
type: Boolean,
|
|
@@ -132,13 +136,25 @@ const props = defineProps({
|
|
|
132
136
|
type: Boolean,
|
|
133
137
|
default: false,
|
|
134
138
|
},
|
|
139
|
+
searchDisabled: {
|
|
140
|
+
type: Boolean,
|
|
141
|
+
default: false,
|
|
142
|
+
},
|
|
135
143
|
teleportToBody: {
|
|
136
144
|
type: Boolean,
|
|
137
145
|
default: false,
|
|
138
146
|
},
|
|
147
|
+
teleportToTop: {
|
|
148
|
+
type: Boolean,
|
|
149
|
+
default: false,
|
|
150
|
+
},
|
|
151
|
+
searchDebounceMs: {
|
|
152
|
+
type: Number,
|
|
153
|
+
default: 300,
|
|
154
|
+
},
|
|
139
155
|
});
|
|
140
156
|
|
|
141
|
-
const emit = defineEmits(['update:modelValue']);
|
|
157
|
+
const emit = defineEmits(['update:modelValue', 'scroll-near-end', 'search']);
|
|
142
158
|
|
|
143
159
|
const search = ref('');
|
|
144
160
|
const showDropdown = ref(false);
|
|
@@ -153,30 +169,39 @@ const dropdownStyle = ref<{ top?: string; }>({
|
|
|
153
169
|
|
|
154
170
|
const selectedItems: Ref<any[]> = ref([]);
|
|
155
171
|
const internalSelect = ref<HTMLElement | null>(null);
|
|
172
|
+
let searchDebounceHandle: ReturnType<typeof setTimeout> | null = null;
|
|
156
173
|
|
|
157
174
|
function inputInput() {
|
|
158
175
|
if (!props.multiple && selectedItems.value.length) {
|
|
159
176
|
selectedItems.value = [];
|
|
160
177
|
emit('update:modelValue', null);
|
|
161
178
|
}
|
|
179
|
+
if (!props.searchDisabled) {
|
|
180
|
+
if (searchDebounceHandle) {
|
|
181
|
+
clearTimeout(searchDebounceHandle);
|
|
182
|
+
}
|
|
183
|
+
searchDebounceHandle = setTimeout(() => {
|
|
184
|
+
emit('search', search.value);
|
|
185
|
+
}, props.searchDebounceMs);
|
|
186
|
+
}
|
|
162
187
|
}
|
|
163
188
|
|
|
164
189
|
function updateFromProps() {
|
|
165
190
|
if (props.modelValue !== undefined) {
|
|
166
191
|
if (!props.multiple) {
|
|
167
|
-
const el = props.options
|
|
192
|
+
const el = props.options?.find((item: any) => item.value === props.modelValue);
|
|
168
193
|
if (el) {
|
|
169
194
|
selectedItems.value = [el];
|
|
170
195
|
} else {
|
|
171
196
|
selectedItems.value = [];
|
|
172
197
|
}
|
|
173
198
|
} else {
|
|
174
|
-
selectedItems.value = props.options
|
|
199
|
+
selectedItems.value = props.options?.filter((item: any) => props.modelValue?.includes(item.value)) || [];
|
|
175
200
|
}
|
|
176
201
|
}
|
|
177
202
|
}
|
|
178
203
|
|
|
179
|
-
function inputClick() {
|
|
204
|
+
async function inputClick() {
|
|
180
205
|
if (props.readonly) return;
|
|
181
206
|
// Toggle local dropdown
|
|
182
207
|
showDropdown.value = !showDropdown.value;
|
|
@@ -184,6 +209,11 @@ function inputClick() {
|
|
|
184
209
|
if (!showDropdown.value && !search.value) {
|
|
185
210
|
search.value = '';
|
|
186
211
|
}
|
|
212
|
+
|
|
213
|
+
if(props.teleportToBody){
|
|
214
|
+
await nextTick();
|
|
215
|
+
handleScroll();
|
|
216
|
+
}
|
|
187
217
|
}
|
|
188
218
|
|
|
189
219
|
watch(
|
|
@@ -221,6 +251,15 @@ const handleScroll = () => {
|
|
|
221
251
|
}
|
|
222
252
|
};
|
|
223
253
|
|
|
254
|
+
const handleDropdownScroll = (event: Event) => {
|
|
255
|
+
const target = event.target as HTMLElement;
|
|
256
|
+
const threshold = 10; // pixels from bottom
|
|
257
|
+
|
|
258
|
+
if (target.scrollTop + target.clientHeight >= target.scrollHeight - threshold) {
|
|
259
|
+
emit('scroll-near-end');
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
|
|
224
263
|
onMounted(() => {
|
|
225
264
|
updateFromProps();
|
|
226
265
|
|
|
@@ -240,8 +279,13 @@ onMounted(() => {
|
|
|
240
279
|
}
|
|
241
280
|
});
|
|
242
281
|
|
|
243
|
-
const filteredItems = computed(() => {
|
|
244
|
-
|
|
282
|
+
const filteredItems: Ref<any[]> = computed(() => {
|
|
283
|
+
|
|
284
|
+
if (props.searchDisabled) {
|
|
285
|
+
return props.options || [];
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
return (props.options || []).filter((item: any) =>
|
|
245
289
|
item.label.toLowerCase().includes(search.value.toLowerCase())
|
|
246
290
|
);
|
|
247
291
|
});
|
|
@@ -262,7 +306,7 @@ const removeClickListener = () => {
|
|
|
262
306
|
document.removeEventListener('click', handleClickOutside);
|
|
263
307
|
};
|
|
264
308
|
|
|
265
|
-
const toogleItem = (item) => {
|
|
309
|
+
const toogleItem = (item: any) => {
|
|
266
310
|
if (selectedItems.value.includes(item)) {
|
|
267
311
|
selectedItems.value = selectedItems.value.filter(i => i.value !== item.value);
|
|
268
312
|
} else {
|
|
@@ -295,6 +339,10 @@ onUnmounted(() => {
|
|
|
295
339
|
if (props.teleportToBody) {
|
|
296
340
|
window.removeEventListener('scroll', handleScroll, true);
|
|
297
341
|
}
|
|
342
|
+
if (searchDebounceHandle) {
|
|
343
|
+
clearTimeout(searchDebounceHandle);
|
|
344
|
+
searchDebounceHandle = null;
|
|
345
|
+
}
|
|
298
346
|
});
|
|
299
347
|
|
|
300
348
|
const getDropdownPosition = computed(() => {
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div v-if="type === 'image'" role="status" class="flex animate-pulse items-center justify-center bg-
|
|
3
|
-
<svg class="w-10 h-10 text-
|
|
2
|
+
<div v-if="type === 'image'" role="status" class="flex animate-pulse items-center justify-center bg-lightSkeletonBackgroundColor rounded dark:bg-darkSkeletonBackgroundColor">
|
|
3
|
+
<svg class="w-10 h-10 text-lightSkeletonIconColor dark:text-darkSkeletonIconColor" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 18">
|
|
4
4
|
<path d="M18 0H2a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2Zm-5.5 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3Zm4.376 10.481A1 1 0 0 1 16 15H4a1 1 0 0 1-.895-1.447l3.5-7A1 1 0 0 1 7.468 6a.965.965 0 0 1 .9.5l2.775 4.757 1.546-1.887a1 1 0 0 1 1.618.1l2.541 4a1 1 0 0 1 .028 1.011Z"/>
|
|
5
5
|
</svg>
|
|
6
6
|
</div>
|
|
7
|
-
<div v-else-if="type === 'video'" role="status" class="flex items-center justify-center max-w-sm bg-
|
|
8
|
-
<svg class="w-10 h-10 text-
|
|
7
|
+
<div v-else-if="type === 'video'" role="status" class="flex items-center justify-center max-w-sm bg-lightSkeletonBackgroundColor rounded-lg animate-pulse dark:bg-darkSkeletonBackgroundColor">
|
|
8
|
+
<svg class="w-10 h-10 text-lightSkeletonIconColor dark:text-darkSkeletonIconColor" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 16 20">
|
|
9
9
|
<path d="M5 5V.13a2.96 2.96 0 0 0-1.293.749L.879 3.707A2.98 2.98 0 0 0 .13 5H5Z"/>
|
|
10
10
|
<path d="M14.066 0H7v5a2 2 0 0 1-2 2H0v11a1.97 1.97 0 0 0 1.934 2h12.132A1.97 1.97 0 0 0 16 18V2a1.97 1.97 0 0 0-1.934-2ZM9 13a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-2a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2Zm4 .382a1 1 0 0 1-1.447.894L10 13v-2l1.553-1.276a1 1 0 0 1 1.447.894v2.764Z"/>
|
|
11
11
|
</svg>
|
|
12
12
|
<span class="sr-only">Loading...</span>
|
|
13
13
|
</div>
|
|
14
|
-
<svg v-else-if="type === 'avatar'" class="me-3 animate-pulse text-
|
|
14
|
+
<svg v-else-if="type === 'avatar'" class="me-3 animate-pulse text-lightSkeletonIconColor dark:text-darkSkeletonBackgroundColor" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
|
|
15
15
|
<path d="M10 0a10 10 0 1 0 10 10A10.011 10.011 0 0 0 10 0Zm0 5a3 3 0 1 1 0 6 3 3 0 0 1 0-6Zm0 13a8.949 8.949 0 0 1-4.951-1.488A3.987 3.987 0 0 1 9 13h2a3.987 3.987 0 0 1 3.951 3.512A8.949 8.949 0 0 1 10 18Z"/>
|
|
16
16
|
</svg>
|
|
17
|
-
<div v-else role="status" class="flex items-center justify-center animate-pulse bg-
|
|
17
|
+
<div v-else role="status" class="flex items-center justify-center animate-pulse bg-lightSkeletonIconColor rounded-full dark:bg-darkSkeletonBackgroundColor">
|
|
18
18
|
<span class="sr-only">Loading...</span>
|
|
19
19
|
</div>
|
|
20
20
|
</template>
|