@platforma-sdk/ui-vue 1.37.7 → 1.37.11
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/.turbo/turbo-build.log +868 -868
- package/.turbo/turbo-type-check.log +1 -1
- package/CHANGELOG.md +16 -0
- package/dist/lib/ui/uikit/dist/components/DataTable/BaseCellComponent.vue.js +2 -2
- package/dist/lib/ui/uikit/dist/components/DataTable/TdCell.vue.js +2 -2
- package/dist/lib/ui/uikit/dist/components/DataTable/composition/useResize.js +2 -2
- package/dist/lib/ui/uikit/dist/components/DataTable/composition/useTableColumns.js +6 -6
- package/dist/lib/ui/uikit/dist/components/DataTable/state.js +12 -12
- package/dist/lib/ui/uikit/dist/components/PlAutocomplete/PlAutocomplete.vue.js +12 -12
- package/dist/lib/ui/uikit/dist/components/PlBtnSplit/PlBtnSplit.vue.js +10 -10
- package/dist/lib/ui/uikit/dist/components/PlBtnSplit/PlBtnSplit.vue.js.map +1 -1
- package/dist/lib/ui/uikit/dist/components/PlElementList/PlElementList.vue.js +10 -0
- package/dist/lib/ui/uikit/dist/components/PlElementList/PlElementList.vue2.js +239 -0
- package/dist/lib/ui/uikit/dist/components/PlElementList/PlElementList.vue2.js.map +1 -0
- package/dist/lib/ui/uikit/dist/components/PlElementList/PlElementList.vue3.js +22 -0
- package/dist/{components → lib/ui/uikit/dist/components}/PlElementList/PlElementList.vue3.js.map +1 -1
- package/dist/lib/ui/uikit/dist/components/PlElementList/PlElementListItem.vue.js +10 -0
- package/dist/lib/ui/uikit/dist/components/PlElementList/PlElementListItem.vue2.js +106 -0
- package/dist/lib/ui/uikit/dist/components/PlElementList/PlElementListItem.vue2.js.map +1 -0
- package/dist/lib/ui/uikit/dist/components/PlElementList/PlElementListItem.vue3.js +48 -0
- package/dist/lib/ui/uikit/dist/components/PlElementList/PlElementListItem.vue3.js.map +1 -0
- package/dist/lib/ui/uikit/dist/components/PlElementList/utils.js +17 -0
- package/dist/lib/ui/uikit/dist/components/PlElementList/utils.js.map +1 -0
- package/dist/lib/ui/uikit/dist/components/PlErrorBoundary/PlErrorBoundary.vue.js +5 -5
- package/dist/lib/ui/uikit/dist/components/PlFileDialog/PlFileDialog.vue.js +14 -14
- package/dist/lib/ui/uikit/dist/components/PlFileDialog/Remote.vue.js +8 -8
- package/dist/lib/ui/uikit/dist/components/PlFileDialog/utils.js +9 -9
- package/dist/lib/ui/uikit/dist/components/PlLogView/PlLogView.vue.js +9 -9
- package/dist/lib/ui/uikit/dist/composition/useFormState.js +5 -5
- package/dist/lib/ui/uikit/dist/composition/useQuery.js +12 -12
- package/dist/lib/ui/uikit/dist/composition/useWatchFetch.js +4 -4
- package/dist/lib/ui/uikit/dist/index.js +81 -78
- package/dist/lib/ui/uikit/dist/index.js.map +1 -1
- package/dist/lib/ui/uikit/dist/lib/util/helpers/dist/index.js +156 -127
- package/dist/lib/ui/uikit/dist/lib/util/helpers/dist/index.js.map +1 -1
- package/dist/lib/ui/uikit/dist/node_modules/.pnpm/@vueuse_core@13.3.0_vue@3.5.13_typescript@5.6.3_/node_modules/@vueuse/core/index.js +53 -43
- package/dist/lib/ui/uikit/dist/node_modules/.pnpm/@vueuse_core@13.3.0_vue@3.5.13_typescript@5.6.3_/node_modules/@vueuse/core/index.js.map +1 -1
- package/dist/lib/ui/uikit/dist/node_modules/.pnpm/@vueuse_integrations@13.3.0_axios@1.8.1_focus-trap@7.6.0_sortablejs@1.15.6_vue@3.5.13_typescript@5.6.3_/node_modules/@vueuse/integrations/useSortable.js +51 -0
- package/dist/lib/ui/uikit/dist/node_modules/.pnpm/@vueuse_integrations@13.3.0_axios@1.8.1_focus-trap@7.6.0_sortablejs@1.15.6_vue@3.5.13_typescript@5.6.3_/node_modules/@vueuse/integrations/useSortable.js.map +1 -0
- package/dist/lib/ui/uikit/dist/node_modules/.pnpm/@vueuse_shared@13.3.0_vue@3.5.13_typescript@5.6.3_/node_modules/@vueuse/shared/index.js +70 -62
- package/dist/lib/ui/uikit/dist/node_modules/.pnpm/@vueuse_shared@13.3.0_vue@3.5.13_typescript@5.6.3_/node_modules/@vueuse/shared/index.js.map +1 -1
- package/dist/lib/ui/uikit/dist/node_modules/.pnpm/sortablejs@1.15.6/node_modules/sortablejs/modular/sortable.esm.js +1262 -0
- package/dist/lib/ui/uikit/dist/node_modules/.pnpm/sortablejs@1.15.6/node_modules/sortablejs/modular/sortable.esm.js.map +1 -0
- package/dist/lib/ui/uikit/dist/sdk/model/dist/index.js +1 -1
- package/dist/lib/ui/uikit/dist/sdk/model/dist/index.js.map +1 -1
- package/dist/lib/ui/uikit/dist/utils/DropdownOverlay/DropdownOverlay.vue.js +2 -2
- package/dist/lib/util/helpers/dist/index.js +43 -85
- package/dist/lib/util/helpers/dist/index.js.map +1 -1
- package/dist/lib.d.ts +0 -1
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +105 -105
- package/dist/node_modules/.pnpm/@vueuse_core@13.3.0_vue@3.5.13_typescript@5.5.4_/node_modules/@vueuse/core/index.js +30 -31
- package/dist/node_modules/.pnpm/@vueuse_core@13.3.0_vue@3.5.13_typescript@5.5.4_/node_modules/@vueuse/core/index.js.map +1 -1
- package/dist/sdk/model/dist/index.js +1 -1
- package/dist/sdk/model/dist/index.js.map +1 -1
- package/package.json +5 -5
- package/src/lib.ts +0 -2
- package/dist/components/PlElementList/PlElementList.vue.d.ts +0 -61
- package/dist/components/PlElementList/PlElementList.vue.d.ts.map +0 -1
- package/dist/components/PlElementList/PlElementList.vue.js +0 -10
- package/dist/components/PlElementList/PlElementList.vue2.js +0 -214
- package/dist/components/PlElementList/PlElementList.vue2.js.map +0 -1
- package/dist/components/PlElementList/PlElementList.vue3.js +0 -13
- package/dist/components/PlElementList/PlElementListItem.vue.d.ts +0 -55
- package/dist/components/PlElementList/PlElementListItem.vue.d.ts.map +0 -1
- package/dist/components/PlElementList/PlElementListItem.vue.js +0 -10
- package/dist/components/PlElementList/PlElementListItem.vue2.js +0 -103
- package/dist/components/PlElementList/PlElementListItem.vue2.js.map +0 -1
- package/dist/components/PlElementList/PlElementListItem.vue3.js +0 -37
- package/dist/components/PlElementList/PlElementListItem.vue3.js.map +0 -1
- package/dist/components/PlElementList/index.d.ts +0 -2
- package/dist/components/PlElementList/index.d.ts.map +0 -1
- package/dist/components/PlElementList/utils.d.ts +0 -3
- package/dist/components/PlElementList/utils.d.ts.map +0 -1
- package/dist/components/PlElementList/utils.js +0 -17
- package/dist/components/PlElementList/utils.js.map +0 -1
- package/dist/node_modules/.pnpm/@vueuse_integrations@13.3.0_axios@1.8.1_focus-trap@7.6.0_sortablejs@1.15.6_vue@3.5.13_typescript@5.5.4_/node_modules/@vueuse/integrations/useSortable.js +0 -51
- package/dist/node_modules/.pnpm/@vueuse_integrations@13.3.0_axios@1.8.1_focus-trap@7.6.0_sortablejs@1.15.6_vue@3.5.13_typescript@5.5.4_/node_modules/@vueuse/integrations/useSortable.js.map +0 -1
- package/dist/node_modules/.pnpm/sortablejs@1.15.6/node_modules/sortablejs/modular/sortable.esm.js +0 -1262
- package/dist/node_modules/.pnpm/sortablejs@1.15.6/node_modules/sortablejs/modular/sortable.esm.js.map +0 -1
- package/src/components/PlElementList/PlElementList.vue +0 -287
- package/src/components/PlElementList/PlElementListItem.vue +0 -222
- package/src/components/PlElementList/README.md +0 -123
- package/src/components/PlElementList/index.ts +0 -1
- package/src/components/PlElementList/utils.ts +0 -17
- /package/dist/{components → lib/ui/uikit/dist/components}/PlElementList/PlElementList.vue.js.map +0 -0
- /package/dist/{components → lib/ui/uikit/dist/components}/PlElementList/PlElementListItem.vue.js.map +0 -0
|
@@ -1,287 +0,0 @@
|
|
|
1
|
-
<script generic="T extends unknown = unknown, K extends number | string = number | string" lang="ts" setup>
|
|
2
|
-
import type { ShallowRef } from 'vue';
|
|
3
|
-
import { computed, shallowRef, watch } from 'vue';
|
|
4
|
-
import { isNil, shallowHash } from '@milaboratories/helpers';
|
|
5
|
-
import { useSortable } from '@vueuse/integrations/useSortable';
|
|
6
|
-
import { type SortableEvent } from 'sortablejs';
|
|
7
|
-
import { moveElements, optionalUpdateRef } from './utils.ts';
|
|
8
|
-
import PlElementListItem from './PlElementListItem.vue';
|
|
9
|
-
|
|
10
|
-
const itemsRef = defineModel<T[]>('items', { required: true });
|
|
11
|
-
const draggableSetRef = defineModel<Set<T>>('draggableItems');
|
|
12
|
-
const removableSetRef = defineModel<Set<T>>('removableItems');
|
|
13
|
-
|
|
14
|
-
const pinnableSetRef = defineModel<Set<T>>('pinnableItems');
|
|
15
|
-
const pinnedSetRef = defineModel<Set<T>>('pinnedItems');
|
|
16
|
-
|
|
17
|
-
const toggableSetRef = defineModel<Set<T>>('toggableItems');
|
|
18
|
-
const toggledSetRef = defineModel<Set<T>>('toggledItems');
|
|
19
|
-
|
|
20
|
-
const props = withDefaults(
|
|
21
|
-
defineProps<{
|
|
22
|
-
getItemKey: (item: T) => K;
|
|
23
|
-
onSort?: (oldIndex: number, newIndex: number) => void | boolean;
|
|
24
|
-
|
|
25
|
-
enableDragging?: boolean;
|
|
26
|
-
onDragEnd?: (oldIndex: number, newIndex: number) => void | boolean;
|
|
27
|
-
|
|
28
|
-
enableRemoving?: boolean;
|
|
29
|
-
onRemove?: (item: T, index: number) => void | boolean;
|
|
30
|
-
|
|
31
|
-
enableToggling?: boolean;
|
|
32
|
-
onToggle?: (item: T, index: number) => void | boolean;
|
|
33
|
-
|
|
34
|
-
enablePinning?: boolean;
|
|
35
|
-
onPin?: (item: T, index: number) => void | boolean;
|
|
36
|
-
}>(), {
|
|
37
|
-
enableDragging: true,
|
|
38
|
-
enableRemoving: undefined,
|
|
39
|
-
enableToggling: true,
|
|
40
|
-
enablePinning: true,
|
|
41
|
-
onSort: undefined,
|
|
42
|
-
onDragEnd: undefined,
|
|
43
|
-
onRemove: undefined,
|
|
44
|
-
onToggle: undefined,
|
|
45
|
-
onPin: undefined,
|
|
46
|
-
},
|
|
47
|
-
);
|
|
48
|
-
|
|
49
|
-
const slots = defineSlots<{
|
|
50
|
-
['item-title']: (props: { item: T; index: number }) => unknown;
|
|
51
|
-
['item-content']?: (props: { item: T; index: number }) => unknown;
|
|
52
|
-
}>();
|
|
53
|
-
|
|
54
|
-
const pinnedItemsRef = computed(() => itemsRef.value.filter(isPinned));
|
|
55
|
-
const hasPinnedItems = computed(() => pinnedItemsRef.value.length > 0);
|
|
56
|
-
|
|
57
|
-
const unpinnedItemsRef = computed(() => itemsRef.value.filter((item) => !isPinned(item)));
|
|
58
|
-
const hasUnpinnedItems = computed(() => unpinnedItemsRef.value.length > 0);
|
|
59
|
-
|
|
60
|
-
const openedSetRef = shallowRef(new Set<T>());
|
|
61
|
-
|
|
62
|
-
const domProjectionItemsRef = shallowRef<undefined | T[]>();
|
|
63
|
-
const pinnedContainerRef = shallowRef<HTMLElement>();
|
|
64
|
-
const unpinnedContainerRef = shallowRef<HTMLElement>();
|
|
65
|
-
|
|
66
|
-
// version fix problem with sync between data and rendered values when items have been changed
|
|
67
|
-
const versionRef = computed<number>((oldVersion) => {
|
|
68
|
-
const currentVersion = shallowHash(...itemsRef.value);
|
|
69
|
-
|
|
70
|
-
if (domProjectionItemsRef.value === undefined) return oldVersion ?? currentVersion;
|
|
71
|
-
|
|
72
|
-
const lastSortedVersion = shallowHash(...domProjectionItemsRef.value);
|
|
73
|
-
|
|
74
|
-
if (currentVersion === lastSortedVersion) return oldVersion ?? currentVersion;
|
|
75
|
-
|
|
76
|
-
return oldVersion !== currentVersion ? currentVersion : lastSortedVersion;
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
createSortable(hasPinnedItems, pinnedContainerRef, pinnedItemsRef, () => 0);
|
|
80
|
-
createSortable(hasUnpinnedItems, unpinnedContainerRef, unpinnedItemsRef, () => pinnedItemsRef.value.length);
|
|
81
|
-
|
|
82
|
-
function createSortable(toggler: ShallowRef<boolean>, elRef: ShallowRef<undefined | HTMLElement>, itemsRef: ShallowRef<T[]>, getOffset: () => number) {
|
|
83
|
-
const sortable = useSortable(elRef, itemsRef, {
|
|
84
|
-
handle: `[data-draggable="true"]`,
|
|
85
|
-
animation: 150,
|
|
86
|
-
forceFallback: true,
|
|
87
|
-
scrollSensitivity: 80,
|
|
88
|
-
forceAutoScrollFallback: true,
|
|
89
|
-
onUpdate: (evt: SortableEvent) => {
|
|
90
|
-
if (evt.oldIndex == null || evt.newIndex == null) {
|
|
91
|
-
throw new Error('Sortable event has no index');
|
|
92
|
-
}
|
|
93
|
-
if (props.onDragEnd?.(evt.oldIndex, evt.newIndex) !== false) {
|
|
94
|
-
moveItems(getOffset() + evt.oldIndex, getOffset() + evt.newIndex, true);
|
|
95
|
-
}
|
|
96
|
-
},
|
|
97
|
-
});
|
|
98
|
-
watch(toggler, (on) => on ? sortable.start() : sortable.stop());
|
|
99
|
-
|
|
100
|
-
return sortable;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
function moveItems(oldIndex: number, newIndex: number, afterUpdateDom: boolean) {
|
|
104
|
-
if (oldIndex === newIndex) return;
|
|
105
|
-
|
|
106
|
-
if (afterUpdateDom) {
|
|
107
|
-
domProjectionItemsRef.value = moveElements(itemsRef.value.slice(), oldIndex, newIndex);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const preventDefault = props.onSort?.(oldIndex, newIndex) === false;
|
|
111
|
-
|
|
112
|
-
if (!preventDefault) {
|
|
113
|
-
moveElements(itemsRef.value, oldIndex, newIndex);
|
|
114
|
-
optionalUpdateRef(itemsRef);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function isDraggable(item: T) {
|
|
119
|
-
if (props.enableDragging === false) return false;
|
|
120
|
-
return (draggableSetRef.value?.has(item) ?? true);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
function isToggable(item: T) {
|
|
124
|
-
if (props.enableToggling === false) return false;
|
|
125
|
-
return !isNil(toggledSetRef.value) && (toggableSetRef.value?.has(item) ?? true);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function isToggled(item: T) {
|
|
129
|
-
return toggledSetRef.value?.has(item) ?? false;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
function isPinnable(item: T) {
|
|
133
|
-
if (props.enablePinning === false) return false;
|
|
134
|
-
return !isNil(pinnedSetRef.value) && (pinnableSetRef.value?.has(item) ?? true);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
function isPinned(item: T) {
|
|
138
|
-
return pinnedSetRef.value?.has(item) ?? false;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
function isOpened(item: T) {
|
|
142
|
-
return openedSetRef.value.has(item);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function isRemovable(item: T) {
|
|
146
|
-
if (props.enableRemoving === false) return false;
|
|
147
|
-
if (removableSetRef.value?.has(item) === false) return false;
|
|
148
|
-
return props.enableRemoving === true || typeof props.onRemove === 'function';
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
function handleToggle(item: T, index: number) {
|
|
152
|
-
if (props.onToggle?.(item, index) === false || isNil(toggledSetRef.value)) return;
|
|
153
|
-
|
|
154
|
-
const toggled = toggledSetRef.value;
|
|
155
|
-
if (toggled.has(item)) toggled.delete(item);
|
|
156
|
-
else toggled.add(item);
|
|
157
|
-
optionalUpdateRef(toggledSetRef);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
function handlePin(item: T, oldIndex: number) {
|
|
161
|
-
if (oldIndex === -1) {
|
|
162
|
-
throw new Error('Pinnable item not found');
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
if (props.onPin?.(item, oldIndex) === false || isNil(pinnedSetRef.value)) return;
|
|
166
|
-
|
|
167
|
-
const pinned = pinnedSetRef.value;
|
|
168
|
-
const alreadyPinned = pinned.has(item);
|
|
169
|
-
if (alreadyPinned) pinned.delete(item);
|
|
170
|
-
else pinned.add(item);
|
|
171
|
-
optionalUpdateRef(pinnedSetRef);
|
|
172
|
-
moveItems(oldIndex, pinned.size + (alreadyPinned ? 0 : -1), false);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
function handleRemove(item: T, index: number) {
|
|
176
|
-
if (props.onRemove?.(item, index) !== false) {
|
|
177
|
-
itemsRef.value.splice(index, 1);
|
|
178
|
-
optionalUpdateRef(itemsRef);
|
|
179
|
-
|
|
180
|
-
if (pinnedSetRef.value?.has(item)) {
|
|
181
|
-
pinnedSetRef.value.delete(item);
|
|
182
|
-
optionalUpdateRef(pinnedSetRef);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
if (toggledSetRef.value?.has(item)) {
|
|
186
|
-
toggledSetRef.value.delete(item);
|
|
187
|
-
optionalUpdateRef(toggledSetRef);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
function handleToggleContent(item: T) {
|
|
193
|
-
const opened = openedSetRef.value;
|
|
194
|
-
if (opened.has(item)) opened.delete(item);
|
|
195
|
-
else opened.add(item);
|
|
196
|
-
optionalUpdateRef(openedSetRef);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// version fix problem with sync between data and rendered values
|
|
200
|
-
const getKey = (item: T) => `${versionRef.value}-${props.getItemKey(item)}`;
|
|
201
|
-
const pinnedKeysRef = computed(() => pinnedItemsRef.value.map(getKey));
|
|
202
|
-
const unpinnedKeysRef = computed(() => unpinnedItemsRef.value.map(getKey));
|
|
203
|
-
|
|
204
|
-
</script>
|
|
205
|
-
|
|
206
|
-
<template>
|
|
207
|
-
<div :class="$style.root">
|
|
208
|
-
<div ref="pinnedContainerRef" :class="$style.list">
|
|
209
|
-
<PlElementListItem
|
|
210
|
-
v-for="(pinnedItem, pinnedIndex) in pinnedItemsRef" :key="pinnedKeysRef[pinnedIndex]"
|
|
211
|
-
:class="$style.item"
|
|
212
|
-
|
|
213
|
-
:index="pinnedIndex"
|
|
214
|
-
:item="pinnedItem"
|
|
215
|
-
:showDragHandle="props.enableDragging"
|
|
216
|
-
:isDraggable="isDraggable(pinnedItem)"
|
|
217
|
-
:isRemovable="isRemovable(pinnedItem)"
|
|
218
|
-
:isToggable="isToggable(pinnedItem)"
|
|
219
|
-
:isToggled="isToggled(pinnedItem)"
|
|
220
|
-
:isPinnable="isPinnable(pinnedItem)"
|
|
221
|
-
:isPinned="isPinned(pinnedItem)"
|
|
222
|
-
:isOpened="isOpened(pinnedItem)"
|
|
223
|
-
|
|
224
|
-
@remove="handleRemove"
|
|
225
|
-
@toggle="handleToggle"
|
|
226
|
-
@pin="handlePin"
|
|
227
|
-
@toggleContent="handleToggleContent"
|
|
228
|
-
>
|
|
229
|
-
<template #title="{ item, index }">
|
|
230
|
-
<slot :index="index" :item="item" name="item-title" />
|
|
231
|
-
</template>
|
|
232
|
-
<template v-if="slots['item-content']" #content="{ item, index }">
|
|
233
|
-
<slot :index="index" :item="item" name="item-content" />
|
|
234
|
-
</template>
|
|
235
|
-
</PlElementListItem>
|
|
236
|
-
</div>
|
|
237
|
-
<div v-if="hasUnpinnedItems" ref="unpinnedContainerRef" :class="$style.list">
|
|
238
|
-
<PlElementListItem
|
|
239
|
-
v-for="(unpinnedItem, unpinnedIndex) in unpinnedItemsRef" :key="unpinnedKeysRef[unpinnedIndex]"
|
|
240
|
-
:class="$style.item"
|
|
241
|
-
|
|
242
|
-
:index="unpinnedIndex + (pinnedSetRef?.size ?? 0)"
|
|
243
|
-
:item="unpinnedItem"
|
|
244
|
-
:showDragHandle="props.enableDragging"
|
|
245
|
-
:isDraggable="isDraggable(unpinnedItem)"
|
|
246
|
-
:isRemovable="isRemovable(unpinnedItem)"
|
|
247
|
-
:isToggable="isToggable(unpinnedItem)"
|
|
248
|
-
:isToggled="isToggled(unpinnedItem)"
|
|
249
|
-
:isPinnable="isPinnable(unpinnedItem)"
|
|
250
|
-
:isPinned="isPinned(unpinnedItem)"
|
|
251
|
-
:isOpened="isOpened(unpinnedItem)"
|
|
252
|
-
|
|
253
|
-
@remove="handleRemove"
|
|
254
|
-
@toggle="handleToggle"
|
|
255
|
-
@pin="handlePin"
|
|
256
|
-
@toggleContent="handleToggleContent"
|
|
257
|
-
>
|
|
258
|
-
<template #title="{ item, index }">
|
|
259
|
-
<slot :index="index" :item="item" name="item-title" />
|
|
260
|
-
</template>
|
|
261
|
-
<template v-if="slots['item-content']" #content="{ item, index }">
|
|
262
|
-
<slot :index="index" :item="item" name="item-content" />
|
|
263
|
-
</template>
|
|
264
|
-
</PlElementListItem>
|
|
265
|
-
</div>
|
|
266
|
-
</div>
|
|
267
|
-
</template>
|
|
268
|
-
|
|
269
|
-
<style module>
|
|
270
|
-
.root, .list {
|
|
271
|
-
display: flex;
|
|
272
|
-
flex-direction: column;
|
|
273
|
-
gap: 8px;
|
|
274
|
-
min-width: 180px;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
.item {
|
|
278
|
-
width: 100%;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
:global(.sortable-ghost) {
|
|
282
|
-
visibility: hidden;
|
|
283
|
-
}
|
|
284
|
-
:global(.sortable-drag) {
|
|
285
|
-
opacity: 1;
|
|
286
|
-
}
|
|
287
|
-
</style>
|
|
@@ -1,222 +0,0 @@
|
|
|
1
|
-
<script generic="T extends unknown = unknown" lang="ts" setup>
|
|
2
|
-
import { computed } from 'vue';
|
|
3
|
-
import { PlIcon16, PlIcon24 } from '@milaboratories/uikit';
|
|
4
|
-
|
|
5
|
-
const props = defineProps<{
|
|
6
|
-
item: T;
|
|
7
|
-
index: number;
|
|
8
|
-
showDragHandle: boolean;
|
|
9
|
-
isDraggable: boolean;
|
|
10
|
-
isRemovable: boolean;
|
|
11
|
-
isToggable: boolean;
|
|
12
|
-
isToggled: boolean;
|
|
13
|
-
isPinnable: boolean;
|
|
14
|
-
isPinned: boolean;
|
|
15
|
-
isOpened: boolean;
|
|
16
|
-
}>();
|
|
17
|
-
|
|
18
|
-
const slots = defineSlots<{
|
|
19
|
-
title: (props: { item: T; index: number }) => unknown;
|
|
20
|
-
content?: (props: { item: T; index: number }) => unknown;
|
|
21
|
-
}>();
|
|
22
|
-
const hasContentSlot = computed(() => slots['content'] !== undefined);
|
|
23
|
-
|
|
24
|
-
const emit = defineEmits<{
|
|
25
|
-
(e: 'toggle', item: T, index: number): void;
|
|
26
|
-
(e: 'pin', item: T, index: number): void;
|
|
27
|
-
(e: 'remove', item: T, index: number): void;
|
|
28
|
-
(e: 'toggleContent', item: T, index: number): void;
|
|
29
|
-
}>();
|
|
30
|
-
</script>
|
|
31
|
-
|
|
32
|
-
<template>
|
|
33
|
-
<div
|
|
34
|
-
:class="[$style.root, {
|
|
35
|
-
[$style.pinned]: props.isPinned,
|
|
36
|
-
[$style.disabled]: props.isToggled,
|
|
37
|
-
}]"
|
|
38
|
-
>
|
|
39
|
-
<div
|
|
40
|
-
:class="[$style.head, {
|
|
41
|
-
[$style.clickable]: hasContentSlot,
|
|
42
|
-
}]"
|
|
43
|
-
@click="emit('toggleContent', props.item, props.index)"
|
|
44
|
-
>
|
|
45
|
-
<div
|
|
46
|
-
v-if="props.showDragHandle"
|
|
47
|
-
:class="[$style.action, $style.draggable, { [$style.disable]: !props.isDraggable } ]"
|
|
48
|
-
:data-draggable="props.isDraggable"
|
|
49
|
-
>
|
|
50
|
-
<PlIcon16 name="drag-dots" />
|
|
51
|
-
</div>
|
|
52
|
-
<PlIcon16 :class="[$style.contentChevron, { [$style.opened]: props.isOpened }]" name="chevron-down" />
|
|
53
|
-
|
|
54
|
-
<div :class="$style.title">
|
|
55
|
-
<slot name="title" :item="props.item" :index="props.index" />
|
|
56
|
-
</div>
|
|
57
|
-
|
|
58
|
-
<div :class="[$style.actions, $style.showOnHover]">
|
|
59
|
-
<div
|
|
60
|
-
v-if="props.isToggable"
|
|
61
|
-
:class="[$style.action, $style.clickable, { [$style.disable]: !props.isToggable }]"
|
|
62
|
-
@click.stop="emit('toggle', props.item, props.index)"
|
|
63
|
-
>
|
|
64
|
-
<PlIcon24 :name="props.isToggled === true ? 'view-hide' : 'view-show'" size="16" />
|
|
65
|
-
</div>
|
|
66
|
-
<div
|
|
67
|
-
v-if="props.isPinnable"
|
|
68
|
-
:class="[$style.action, $style.clickable, {
|
|
69
|
-
[$style.disable]: !props.isPinnable,
|
|
70
|
-
[$style.activated]: props.isPinned,
|
|
71
|
-
}]"
|
|
72
|
-
@click.stop="emit('pin', props.item, props.index)"
|
|
73
|
-
>
|
|
74
|
-
<PlIcon24 name="pin" size="16" />
|
|
75
|
-
</div>
|
|
76
|
-
<div
|
|
77
|
-
v-if="props.isRemovable"
|
|
78
|
-
:class="[$style.action, $style.clickable]"
|
|
79
|
-
@click.stop="emit('remove', props.item, props.index)"
|
|
80
|
-
>
|
|
81
|
-
<PlIcon16 name="close" />
|
|
82
|
-
</div>
|
|
83
|
-
</div>
|
|
84
|
-
</div>
|
|
85
|
-
<div v-if="hasContentSlot && isOpened" :class="$style.body">
|
|
86
|
-
<slot name="content" :item="props.item" :index="props.index" />
|
|
87
|
-
</div>
|
|
88
|
-
</div>
|
|
89
|
-
</template>
|
|
90
|
-
|
|
91
|
-
<style module>
|
|
92
|
-
.root {
|
|
93
|
-
--background: rgba(255, 255, 255, 0.8);
|
|
94
|
-
--border-color: var(--color-div-grey);
|
|
95
|
-
--head-background: unset;
|
|
96
|
-
--box-shadow: none;
|
|
97
|
-
--box-shadow-active: 0 0 0 4px color-mix(in srgb, var(--border-color-focus) 50%, transparent);
|
|
98
|
-
|
|
99
|
-
&:global(.sortable-drag),
|
|
100
|
-
&:global(.sortable-chosen) {
|
|
101
|
-
--head-background: var(--gradient-light-lime);
|
|
102
|
-
--border-color: var(--border-color-focus);
|
|
103
|
-
--box-shadow: var(--box-shadow-active)
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
.root {
|
|
107
|
-
display: flex;
|
|
108
|
-
flex-direction: column;
|
|
109
|
-
justify-content: center;
|
|
110
|
-
border-radius: var(--border-radius);
|
|
111
|
-
border: 1px solid var(--border-color);
|
|
112
|
-
background-color: var(--background);
|
|
113
|
-
transition: box-shadow 0.15s;
|
|
114
|
-
box-shadow: var(--box-shadow);
|
|
115
|
-
|
|
116
|
-
&:hover {
|
|
117
|
-
--border-color: var(--border-color-focus);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
&.disabled {
|
|
121
|
-
opacity: 0.6;
|
|
122
|
-
filter: grayscale(1);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
&.pinned {
|
|
126
|
-
--background: var(--bg-base-light);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
.head {
|
|
131
|
-
position: relative;
|
|
132
|
-
display: flex;
|
|
133
|
-
align-items: center;
|
|
134
|
-
padding: 8px;
|
|
135
|
-
border-radius: var(--border-radius) var(--border-radius) 0 0;
|
|
136
|
-
background: var(--head-background);
|
|
137
|
-
|
|
138
|
-
&:hover, &.opened {
|
|
139
|
-
--head-background: var(--gradient-light-lime);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
.contentChevron {
|
|
144
|
-
display: block;
|
|
145
|
-
width: 16px;
|
|
146
|
-
height: 16px;
|
|
147
|
-
margin-right: 4px;
|
|
148
|
-
transform: rotate(-90deg);
|
|
149
|
-
transition: transform 0.15s;
|
|
150
|
-
|
|
151
|
-
&.opened {
|
|
152
|
-
transform: rotate(0deg);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
.title {
|
|
157
|
-
display: block;
|
|
158
|
-
max-width: calc(100% - 50px);
|
|
159
|
-
overflow: hidden;
|
|
160
|
-
text-overflow: ellipsis;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
.body {
|
|
164
|
-
padding: 24px;
|
|
165
|
-
border-radius: 0 0 var(--border-radius) var(--border-radius);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
.actions {
|
|
169
|
-
position: absolute;
|
|
170
|
-
top: 8px;
|
|
171
|
-
right: 8px;
|
|
172
|
-
display: flex;
|
|
173
|
-
align-items: center;
|
|
174
|
-
background-color: var(--background);
|
|
175
|
-
border-radius: var(--border-radius);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
.action {
|
|
179
|
-
width: 24px;
|
|
180
|
-
height: 24px;
|
|
181
|
-
padding: 4px; /* use padding instead of gap on parent, for better accessibility */
|
|
182
|
-
opacity: 0.6;
|
|
183
|
-
border-radius: var(--border-radius);
|
|
184
|
-
transition: all 0.15s;
|
|
185
|
-
|
|
186
|
-
svg {
|
|
187
|
-
width: 16px;
|
|
188
|
-
height: 16px;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
&:hover {
|
|
192
|
-
opacity: 1;
|
|
193
|
-
background-color: var(--bg-elevated-02);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
&.activated {
|
|
197
|
-
opacity: 0.8;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
&.disable {
|
|
201
|
-
cursor: not-allowed;
|
|
202
|
-
opacity: 0.4;
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
.clickable {
|
|
207
|
-
cursor: pointer;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
.draggable {
|
|
211
|
-
cursor: grab;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
.showOnHover {
|
|
215
|
-
opacity: 0;
|
|
216
|
-
transition: opacity 0.15s;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
.root:hover .showOnHover {
|
|
220
|
-
opacity: 1;
|
|
221
|
-
}
|
|
222
|
-
</style>
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
PlElementList.vue
|
|
2
|
-
=================
|
|
3
|
-
A **generic, feature-rich list component** that supports drag-and-drop re-ordering,
|
|
4
|
-
pin/unpin, expand/collapse, and optional removal of items. Written in the
|
|
5
|
-
`<script setup lang="ts">` style and fully type-safe thanks to the generic
|
|
6
|
-
parameters **`T`** (item type) and **`K`** (key type).
|
|
7
|
-
---------------------------------------------------------------------------
|
|
8
|
-
|
|
9
|
-
1. GENERICS
|
|
10
|
-
|
|
11
|
-
---------------------------------------------------------------------------
|
|
12
|
-
• **`T`** – Runtime type of a single list element
|
|
13
|
-
• **`K`** – Type returned by `getItemKey` (typically `string` or `number`)
|
|
14
|
-
---------------------------------------------------------------------------
|
|
15
|
-
|
|
16
|
-
2. TWO-WAY BINDINGS (`v-model`)
|
|
17
|
-
|
|
18
|
-
---------------------------------------------------------------------------
|
|
19
|
-
|
|
20
|
-
| Model name | Type | Purpose / Behaviour |
|
|
21
|
-
|------------------|----------|--------------------------------------------------------|
|
|
22
|
-
| `items`* | `T[]` | Source array; the list you render & mutate |
|
|
23
|
-
| `draggableItems` | `Set<T>` | Restricts which items may be dragged |
|
|
24
|
-
| `removableItems` | `Set<T>` | Restricts which items may be removed |
|
|
25
|
-
| `pinnableItems` | `Set<T>` | Restricts which items may be pinned |
|
|
26
|
-
| `pinnedItems` | `Set<T>` | Tracks the *current* pinned elements |
|
|
27
|
-
| `toggableItems` | `Set<T>` | Restricts which items may be toggled (expand/collapse) |
|
|
28
|
-
| `toggledItems` | `Set<T>` | Tracks the expand/collapse state per item |
|
|
29
|
-
|
|
30
|
-
(*required)
|
|
31
|
-
All sets are **fully replaceable**; assign a new `Set()` to trigger re-render.
|
|
32
|
-
---------------------------------------------------------------------------
|
|
33
|
-
|
|
34
|
-
3. PROPS
|
|
35
|
-
|
|
36
|
-
---------------------------------------------------------------------------
|
|
37
|
-
|
|
38
|
-
| Prop | Type | Default | Notes |
|
|
39
|
-
|------------------|-----------------------------------------------------------|-------------|-------------------------------------------------|
|
|
40
|
-
| `getItemKey`* | `(item:T) ⇒ K` | — | Stable key for `v-for` & SortableJS |
|
|
41
|
-
| **Sorting** | | | |
|
|
42
|
-
| `onSort` | `(sorted:T[], oldIdx:number, newIdx:number) ⇒ void\|bool` | — | Return **false** to cancel applying new order |
|
|
43
|
-
| **Dragging** | | | |
|
|
44
|
-
| `enableDragging` | `boolean` | `true` | Master switch |
|
|
45
|
-
| `onDragEnd` | `(oldIdx:number, newIdx:number) ⇒ void\|bool` | — | Fired by SortableJS; return **false** to ignore |
|
|
46
|
-
| **Removing** | | | |
|
|
47
|
-
| `enableRemoving` | `boolean` | `undefined` | `true` ⇒ always show remove, `false` ⇒ never |
|
|
48
|
-
| `onRemove` | `(item:T, index:number) ⇒ void\|bool` | — | Return **false** to veto |
|
|
49
|
-
| **Toggling** | | | |
|
|
50
|
-
| `enableToggling` | `boolean` | `true` | Master switch |
|
|
51
|
-
| `onToggle` | `(item:T, index:number) ⇒ void\|bool` | — | Return **false** to veto |
|
|
52
|
-
| **Pinning** | | | |
|
|
53
|
-
| `enablePinning` | `boolean` | `true` | Master switch |
|
|
54
|
-
| `onPin` | `(item:T, index:number) ⇒ void\|bool` | — | Return **false** to veto |
|
|
55
|
-
|
|
56
|
-
---------------------------------------------------------------------------
|
|
57
|
-
|
|
58
|
-
4. SLOTS
|
|
59
|
-
|
|
60
|
-
---------------------------------------------------------------------------
|
|
61
|
-
|
|
62
|
-
- **`item-title`** – **required**. Receives `{ item, index }`.
|
|
63
|
-
- **`item-content`** – optional. Same slot props; rendered only when the item
|
|
64
|
-
is in the “opened” state (`toggleContent` event).
|
|
65
|
-
|
|
66
|
-
---------------------------------------------------------------------------
|
|
67
|
-
|
|
68
|
-
5. EVENTS EMITTED BY `<PlElementListItem>`
|
|
69
|
-
|
|
70
|
-
---------------------------------------------------------------------------
|
|
71
|
-
`remove`, `toggle`, `pin`, `toggleContent` – all bubble up with
|
|
72
|
-
`(item:T, index:number)` so you can hook into your own logic if the higher-level
|
|
73
|
-
callbacks are not enough.
|
|
74
|
-
---------------------------------------------------------------------------
|
|
75
|
-
|
|
76
|
-
6. BEHAVIOUR SUMMARY
|
|
77
|
-
|
|
78
|
-
---------------------------------------------------------------------------
|
|
79
|
-
|
|
80
|
-
- **Drag-and-drop** – powered by `useSortable()` (SortableJS).
|
|
81
|
-
- **Pinning** – moves an item between “pinned” and “unpinned” regions; the two
|
|
82
|
-
regions render in separate `<div>` containers for visual clarity.
|
|
83
|
-
- **Toggling** – expands/collapses the content slot and updates `toggledItems`.
|
|
84
|
-
- **Removing** – deletes the item from `items` after `onRemove` (if supplied)
|
|
85
|
-
resolves to anything except `false`.
|
|
86
|
-
- **Versioning** (`versionRef`) – a shallow hash of the items array keeps Vue
|
|
87
|
-
keys stable even when the array reference itself is unchanged but content
|
|
88
|
-
reorders.
|
|
89
|
-
|
|
90
|
-
---------------------------------------------------------------------------
|
|
91
|
-
|
|
92
|
-
7. EXAMPLE USAGE
|
|
93
|
-
|
|
94
|
-
---------------------------------------------------------------------------
|
|
95
|
-
|
|
96
|
-
```vue
|
|
97
|
-
|
|
98
|
-
<PlElementList
|
|
99
|
-
v-model:items="elements"
|
|
100
|
-
v-model:pinnedItems="pinned"
|
|
101
|
-
v-model:toggledItems="opened"
|
|
102
|
-
:getItemKey="el => el.id"
|
|
103
|
-
:onSort="(newArr) => api.saveOrder(newArr)"
|
|
104
|
-
>
|
|
105
|
-
<template #item-title="{ item }">
|
|
106
|
-
{{ item.name }}
|
|
107
|
-
</template>
|
|
108
|
-
<template #item-content="{ item }">
|
|
109
|
-
<pre>{{ JSON.stringify(item.meta, null, 2) }}</pre>
|
|
110
|
-
</template>
|
|
111
|
-
</PlElementList>
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
---------------------------------------------------------------------------
|
|
115
|
-
|
|
116
|
-
8. CAVEATS
|
|
117
|
-
|
|
118
|
-
---------------------------------------------------------------------------
|
|
119
|
-
|
|
120
|
-
1. Each item **must** be referentially stable or provide a deterministic key.
|
|
121
|
-
2. Never mutate `items` in place; always assign a new array to preserve reactivity.
|
|
122
|
-
3. Indexes supplied to callbacks are **visual** indexes (pinned items are listed
|
|
123
|
-
first).
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default as PlElementList } from './PlElementList.vue';
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { isRef, isShallow } from 'vue';
|
|
2
|
-
import { shallowClone } from '@milaboratories/helpers';
|
|
3
|
-
|
|
4
|
-
export const moveElements = <T>(array: T[], from: number, to: number): T[] => {
|
|
5
|
-
if (to >= 0 && to < array.length) {
|
|
6
|
-
const element = array.splice(from, 1)[0];
|
|
7
|
-
array.splice(to, 0, element);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
return array;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
export function optionalUpdateRef<T>(ref: T) {
|
|
14
|
-
if (isRef(ref) && isShallow(ref)) {
|
|
15
|
-
ref.value = shallowClone(ref.value);
|
|
16
|
-
}
|
|
17
|
-
}
|
/package/dist/{components → lib/ui/uikit/dist/components}/PlElementList/PlElementList.vue.js.map
RENAMED
|
File without changes
|
/package/dist/{components → lib/ui/uikit/dist/components}/PlElementList/PlElementListItem.vue.js.map
RENAMED
|
File without changes
|