adminforth 1.13.0-next.33 → 1.13.0-next.35

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.
@@ -98,4 +98,17 @@ onUnmounted(() => {
98
98
  modal.value?.destroy();
99
99
  })
100
100
 
101
+ function open() {
102
+ modal.value?.show();
103
+ }
104
+
105
+ function close() {
106
+ modal.value?.hide();
107
+ }
108
+
109
+ defineExpose({
110
+ open: open,
111
+ close: close,
112
+ })
113
+
101
114
  </script>
@@ -34,7 +34,7 @@
34
34
  </div>
35
35
  <teleport to="body" v-if="teleportToBody && showDropdown">
36
36
  <div ref="dropdownEl" :style="getDropdownPosition" :class="{'shadow-none': isTop}"
37
- class="fixed z-50 w-full bg-white shadow-lg dark:shadow-black dark:bg-gray-700
37
+ class="fixed z-[5] w-full bg-white shadow-lg dark:shadow-black dark:bg-gray-700
38
38
  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
39
  <div
40
40
  v-for="item in filteredItems"
@@ -202,6 +202,23 @@ watch(
202
202
  }
203
203
  );
204
204
 
205
+ const handleScroll = () => {
206
+ if (showDropdown.value && inputEl.value) {
207
+ const rect = inputEl.value.getBoundingClientRect();
208
+ const style = {
209
+ left: `${rect.left}px`,
210
+ top: isTop.value && dropdownHeight.value
211
+ ? `${rect.top - dropdownHeight.value - 8}px`
212
+ : `${rect.bottom + 8}px`,
213
+ width: `${rect.width}px`
214
+ };
215
+
216
+ if (dropdownEl.value) {
217
+ Object.assign(dropdownEl.value.style, style);
218
+ }
219
+ }
220
+ };
221
+
205
222
  onMounted(() => {
206
223
  updateFromProps();
207
224
 
@@ -214,7 +231,11 @@ onMounted(() => {
214
231
  });
215
232
 
216
233
  addClickListener();
217
-
234
+
235
+ // Add scroll listeners if teleportToBody is true
236
+ if (props.teleportToBody) {
237
+ window.addEventListener('scroll', handleScroll, true);
238
+ }
218
239
  });
219
240
 
220
241
  const filteredItems = computed(() => {
@@ -268,6 +289,10 @@ const toogleItem = (item) => {
268
289
 
269
290
  onUnmounted(() => {
270
291
  removeClickListener();
292
+ // Remove scroll listeners if teleportToBody is true
293
+ if (props.teleportToBody) {
294
+ window.removeEventListener('scroll', handleScroll, true);
295
+ }
271
296
  });
272
297
 
273
298
  const getDropdownPosition = computed(() => {
@@ -18,6 +18,7 @@
18
18
  ref="input"
19
19
  class="w-full"
20
20
  :options="columnOptions[column.name] || []"
21
+ teleportToBody
21
22
  :placeholder = "columnOptions[column.name]?.length ?$t('Select...'): $t('There are no options available')"
22
23
  :modelValue="value"
23
24
  :readonly="column.editReadonly && source === 'edit'"
@@ -28,6 +29,7 @@
28
29
  ref="input"
29
30
  class="w-full"
30
31
  :options="column.enum"
32
+ teleportToBody
31
33
  :modelValue="value"
32
34
  :readonly="column.editReadonly && source === 'edit'"
33
35
  @update:modelValue="$emit('update:modelValue', $event)"
@@ -37,6 +39,7 @@
37
39
  ref="input"
38
40
  class="w-full"
39
41
  :options="getBooleanOptions(column)"
42
+ teleportToBody
40
43
  :modelValue="value"
41
44
  :readonly="column.editReadonly && source === 'edit'"
42
45
  @update:modelValue="$emit('update:modelValue', $event)"
@@ -0,0 +1,75 @@
1
+ <template>
2
+ <template v-if="column.isArray?.enabled">
3
+ <div class="flex flex-col">
4
+ <ColumnValueInput
5
+ v-for="(arrayItemValue, arrayItemIndex) in currentValues[column.name]"
6
+ :key="`${column.name}-${arrayItemIndex}`"
7
+ ref="arrayItemRefs"
8
+ :class="{'mt-2': arrayItemIndex}"
9
+ :source="source"
10
+ :column="column"
11
+ :type="column.isArray.itemType"
12
+ :value="arrayItemValue"
13
+ :currentValues="currentValues"
14
+ :mode="mode"
15
+ :columnOptions="columnOptions"
16
+ :deletable="!column.editReadonly"
17
+ @update:modelValue="setCurrentValue(column.name, $event, arrayItemIndex)"
18
+ @update:unmasked="$emit('update:unmasked', column.name)"
19
+ @update:inValidity="$emit('update:inValidity', { name: column.name, value: $event })"
20
+ @update:emptiness="$emit('update:emptiness', { name: column.name, value: $event })"
21
+ @delete="setCurrentValue(column.name, currentValues[column.name].filter((_, index) => index !== arrayItemIndex))"
22
+ />
23
+ </div>
24
+ <button
25
+ v-if="!column.editReadonly"
26
+ type="button"
27
+ @click="addArrayItem"
28
+ class="flex items-center py-1 px-3 me-2 text-sm font-medium rounded-default text-gray-900 focus:outline-none bg-white rounded border border-gray-300 hover:bg-gray-100 hover:text-lightPrimary focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
29
+ :class="{'mt-2': currentValues[column.name].length}"
30
+ >
31
+ <IconPlusOutline class="w-4 h-4 me-2"/>
32
+ {{ $t('Add') }}
33
+ </button>
34
+ </template>
35
+ <ColumnValueInput
36
+ v-else
37
+ :source="source"
38
+ :column="column"
39
+ :value="currentValues[column.name]"
40
+ :currentValues="currentValues"
41
+ :mode="mode"
42
+ :columnOptions="columnOptions"
43
+ :unmasked="unmasked"
44
+ @update:modelValue="setCurrentValue(column.name, $event)"
45
+ @update:unmasked="$emit('update:unmasked', column.name)"
46
+ @update:inValidity="$emit('update:inValidity', { name: column.name, value: $event })"
47
+ @update:emptiness="$emit('update:emptiness', { name: column.name, value: $event })"
48
+ />
49
+ </template>
50
+
51
+ <script setup lang="ts">
52
+ import { IconPlusOutline } from '@iconify-prerendered/vue-flowbite';
53
+ import ColumnValueInput from "./ColumnValueInput.vue";
54
+ import { ref, nextTick } from 'vue';
55
+
56
+ const props = defineProps<{
57
+ source: 'create' | 'edit',
58
+ column: any,
59
+ currentValues: any,
60
+ mode: string,
61
+ columnOptions: any,
62
+ unmasked: any,
63
+ setCurrentValue: Function
64
+ }>();
65
+
66
+ const emit = defineEmits(['update:unmasked', 'update:inValidity', 'update:emptiness', 'focus-last-input']);
67
+
68
+ const arrayItemRefs = ref([]);
69
+
70
+ async function addArrayItem() {
71
+ props.setCurrentValue(props.column.name, props.currentValues[props.column.name], props.currentValues[props.column.name].length);
72
+ await nextTick();
73
+ arrayItemRefs.value[arrayItemRefs.value.length - 1].focus();
74
+ }
75
+ </script>
@@ -42,50 +42,17 @@
42
42
  class="px-6 py-4 whitespace-pre-wrap relative block md:table-cell"
43
43
  :class="{'rounded-br-lg': i === group.columns.length - 1}"
44
44
  >
45
- <template v-if="column.isArray?.enabled">
46
- <ColumnValueInput
47
- v-for="(arrayItemValue, arrayItemIndex) in currentValues[column.name]"
48
- :key="`${column.name}-${arrayItemIndex}`"
49
- ref="arrayItemRefs"
50
- :class="{'mt-2': arrayItemIndex}"
51
- :source="source"
52
- :column="column"
53
- :type="column.isArray.itemType"
54
- :value="arrayItemValue"
55
- :currentValues="currentValues"
56
- :mode="mode"
57
- :columnOptions="columnOptions"
58
- :deletable="!column.editReadonly"
59
- @update:modelValue="setCurrentValue(column.name, $event, arrayItemIndex)"
60
- @update:unmasked="unmasked[column.name] = !unmasked[column.name]"
61
- @update:inValidity="customComponentsInValidity[column.name] = $event"
62
- @update:emptiness="customComponentsEmptiness[column.name] = $event"
63
- @delete="setCurrentValue(column.name, currentValues[column.name].filter((_, index) => index !== arrayItemIndex))"
64
- />
65
- <button
66
- v-if="!column.editReadonly"
67
- type="button"
68
- @click="setCurrentValue(column.name, currentValues[column.name], currentValues[column.name].length); focusOnLastInput(column.name)"
69
- class="flex items-center py-1 px-3 me-2 text-sm font-medium rounded-default text-gray-900 focus:outline-none bg-white rounded border border-gray-300 hover:bg-gray-100 hover:text-lightPrimary focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
70
- :class="{'mt-2': currentValues[column.name].length}"
71
- >
72
- <IconPlusOutline class="w-4 h-4 me-2"/>
73
- {{ $t('Add') }}
74
- </button>
75
- </template>
76
- <ColumnValueInput
77
- v-else
45
+ <ColumnValueInputWrapper
78
46
  :source="source"
79
47
  :column="column"
80
- :value="currentValues[column.name]"
81
48
  :currentValues="currentValues"
82
49
  :mode="mode"
83
50
  :columnOptions="columnOptions"
84
51
  :unmasked="unmasked"
85
- @update:modelValue="setCurrentValue(column.name, $event)"
86
- @update:unmasked="unmasked[column.name] = !unmasked[column.name]"
87
- @update:inValidity="customComponentsInValidity[column.name] = $event"
88
- @update:emptiness="customComponentsEmptiness[column.name] = $event"
52
+ :setCurrentValue="setCurrentValue"
53
+ @update:unmasked="unmasked[$event] = !unmasked[$event]"
54
+ @update:inValidity="customComponentsInValidity[$event.name] = $event.value"
55
+ @update:emptiness="customComponentsEmptiness[$event.name] = $event.value"
89
56
  />
90
57
  <div v-if="columnError(column) && validating" class="mt-1 text-xs text-red-500 dark:text-red-400">{{ columnError(column) }}</div>
91
58
  <div v-if="column.editingNote && column.editingNote[mode]" class="mt-1 text-xs text-gray-400 dark:text-gray-500">{{ column.editingNote[mode] }}</div>
@@ -98,10 +65,10 @@
98
65
 
99
66
  <script setup lang="ts">
100
67
  import { IconExclamationCircleSolid, IconPlusOutline } from '@iconify-prerendered/vue-flowbite';
101
- import ColumnValueInput from "@/components/ColumnValueInput.vue";
102
68
  import { Tooltip } from '@/afcl';
103
69
  import { ref, computed, watch, nextTick, type Ref } from 'vue';
104
70
  import { useI18n } from 'vue-i18n';
71
+ import ColumnValueInputWrapper from "@/components/ColumnValueInputWrapper.vue";
105
72
 
106
73
  const { t } = useI18n();
107
74
 
@@ -117,8 +84,6 @@
117
84
  columnOptions: any,
118
85
  }>();
119
86
 
120
- const arrayItemRefs = ref([]);
121
-
122
87
  const customComponentsInValidity: Ref<Record<string, boolean>> = ref({});
123
88
  const customComponentsEmptiness: Ref<Record<string, boolean>> = ref({});
124
89
  const allColumnsHaveCustomComponent = computed(() => {
@@ -130,12 +95,6 @@
130
95
 
131
96
  const emit = defineEmits(['update:customComponentsInValidity', 'update:customComponentsEmptiness']);
132
97
 
133
- async function focusOnLastInput(column) {
134
- // wait for element to register
135
- await nextTick();
136
- arrayItemRefs.value[arrayItemRefs.value.length - 1].focus();
137
- }
138
-
139
98
  watch(customComponentsInValidity.value, (newVal) => {
140
99
  emit('update:customComponentsInValidity', newVal);
141
100
  });
@@ -144,4 +103,4 @@
144
103
  emit('update:customComponentsEmptiness', newVal);
145
104
  });
146
105
 
147
- </script>
106
+ </script>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adminforth",
3
- "version": "1.13.0-next.33",
3
+ "version": "1.13.0-next.35",
4
4
  "description": "OpenSource Vue3 powered forth-generation admin panel",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",