@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.
Files changed (87) hide show
  1. package/.turbo/turbo-build.log +868 -868
  2. package/.turbo/turbo-type-check.log +1 -1
  3. package/CHANGELOG.md +16 -0
  4. package/dist/lib/ui/uikit/dist/components/DataTable/BaseCellComponent.vue.js +2 -2
  5. package/dist/lib/ui/uikit/dist/components/DataTable/TdCell.vue.js +2 -2
  6. package/dist/lib/ui/uikit/dist/components/DataTable/composition/useResize.js +2 -2
  7. package/dist/lib/ui/uikit/dist/components/DataTable/composition/useTableColumns.js +6 -6
  8. package/dist/lib/ui/uikit/dist/components/DataTable/state.js +12 -12
  9. package/dist/lib/ui/uikit/dist/components/PlAutocomplete/PlAutocomplete.vue.js +12 -12
  10. package/dist/lib/ui/uikit/dist/components/PlBtnSplit/PlBtnSplit.vue.js +10 -10
  11. package/dist/lib/ui/uikit/dist/components/PlBtnSplit/PlBtnSplit.vue.js.map +1 -1
  12. package/dist/lib/ui/uikit/dist/components/PlElementList/PlElementList.vue.js +10 -0
  13. package/dist/lib/ui/uikit/dist/components/PlElementList/PlElementList.vue2.js +239 -0
  14. package/dist/lib/ui/uikit/dist/components/PlElementList/PlElementList.vue2.js.map +1 -0
  15. package/dist/lib/ui/uikit/dist/components/PlElementList/PlElementList.vue3.js +22 -0
  16. package/dist/{components → lib/ui/uikit/dist/components}/PlElementList/PlElementList.vue3.js.map +1 -1
  17. package/dist/lib/ui/uikit/dist/components/PlElementList/PlElementListItem.vue.js +10 -0
  18. package/dist/lib/ui/uikit/dist/components/PlElementList/PlElementListItem.vue2.js +106 -0
  19. package/dist/lib/ui/uikit/dist/components/PlElementList/PlElementListItem.vue2.js.map +1 -0
  20. package/dist/lib/ui/uikit/dist/components/PlElementList/PlElementListItem.vue3.js +48 -0
  21. package/dist/lib/ui/uikit/dist/components/PlElementList/PlElementListItem.vue3.js.map +1 -0
  22. package/dist/lib/ui/uikit/dist/components/PlElementList/utils.js +17 -0
  23. package/dist/lib/ui/uikit/dist/components/PlElementList/utils.js.map +1 -0
  24. package/dist/lib/ui/uikit/dist/components/PlErrorBoundary/PlErrorBoundary.vue.js +5 -5
  25. package/dist/lib/ui/uikit/dist/components/PlFileDialog/PlFileDialog.vue.js +14 -14
  26. package/dist/lib/ui/uikit/dist/components/PlFileDialog/Remote.vue.js +8 -8
  27. package/dist/lib/ui/uikit/dist/components/PlFileDialog/utils.js +9 -9
  28. package/dist/lib/ui/uikit/dist/components/PlLogView/PlLogView.vue.js +9 -9
  29. package/dist/lib/ui/uikit/dist/composition/useFormState.js +5 -5
  30. package/dist/lib/ui/uikit/dist/composition/useQuery.js +12 -12
  31. package/dist/lib/ui/uikit/dist/composition/useWatchFetch.js +4 -4
  32. package/dist/lib/ui/uikit/dist/index.js +81 -78
  33. package/dist/lib/ui/uikit/dist/index.js.map +1 -1
  34. package/dist/lib/ui/uikit/dist/lib/util/helpers/dist/index.js +156 -127
  35. package/dist/lib/ui/uikit/dist/lib/util/helpers/dist/index.js.map +1 -1
  36. 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
  37. 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
  38. 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
  39. 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
  40. 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
  41. 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
  42. package/dist/lib/ui/uikit/dist/node_modules/.pnpm/sortablejs@1.15.6/node_modules/sortablejs/modular/sortable.esm.js +1262 -0
  43. package/dist/lib/ui/uikit/dist/node_modules/.pnpm/sortablejs@1.15.6/node_modules/sortablejs/modular/sortable.esm.js.map +1 -0
  44. package/dist/lib/ui/uikit/dist/sdk/model/dist/index.js +1 -1
  45. package/dist/lib/ui/uikit/dist/sdk/model/dist/index.js.map +1 -1
  46. package/dist/lib/ui/uikit/dist/utils/DropdownOverlay/DropdownOverlay.vue.js +2 -2
  47. package/dist/lib/util/helpers/dist/index.js +43 -85
  48. package/dist/lib/util/helpers/dist/index.js.map +1 -1
  49. package/dist/lib.d.ts +0 -1
  50. package/dist/lib.d.ts.map +1 -1
  51. package/dist/lib.js +105 -105
  52. 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
  53. 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
  54. package/dist/sdk/model/dist/index.js +1 -1
  55. package/dist/sdk/model/dist/index.js.map +1 -1
  56. package/package.json +5 -5
  57. package/src/lib.ts +0 -2
  58. package/dist/components/PlElementList/PlElementList.vue.d.ts +0 -61
  59. package/dist/components/PlElementList/PlElementList.vue.d.ts.map +0 -1
  60. package/dist/components/PlElementList/PlElementList.vue.js +0 -10
  61. package/dist/components/PlElementList/PlElementList.vue2.js +0 -214
  62. package/dist/components/PlElementList/PlElementList.vue2.js.map +0 -1
  63. package/dist/components/PlElementList/PlElementList.vue3.js +0 -13
  64. package/dist/components/PlElementList/PlElementListItem.vue.d.ts +0 -55
  65. package/dist/components/PlElementList/PlElementListItem.vue.d.ts.map +0 -1
  66. package/dist/components/PlElementList/PlElementListItem.vue.js +0 -10
  67. package/dist/components/PlElementList/PlElementListItem.vue2.js +0 -103
  68. package/dist/components/PlElementList/PlElementListItem.vue2.js.map +0 -1
  69. package/dist/components/PlElementList/PlElementListItem.vue3.js +0 -37
  70. package/dist/components/PlElementList/PlElementListItem.vue3.js.map +0 -1
  71. package/dist/components/PlElementList/index.d.ts +0 -2
  72. package/dist/components/PlElementList/index.d.ts.map +0 -1
  73. package/dist/components/PlElementList/utils.d.ts +0 -3
  74. package/dist/components/PlElementList/utils.d.ts.map +0 -1
  75. package/dist/components/PlElementList/utils.js +0 -17
  76. package/dist/components/PlElementList/utils.js.map +0 -1
  77. 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
  78. 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
  79. package/dist/node_modules/.pnpm/sortablejs@1.15.6/node_modules/sortablejs/modular/sortable.esm.js +0 -1262
  80. package/dist/node_modules/.pnpm/sortablejs@1.15.6/node_modules/sortablejs/modular/sortable.esm.js.map +0 -1
  81. package/src/components/PlElementList/PlElementList.vue +0 -287
  82. package/src/components/PlElementList/PlElementListItem.vue +0 -222
  83. package/src/components/PlElementList/README.md +0 -123
  84. package/src/components/PlElementList/index.ts +0 -1
  85. package/src/components/PlElementList/utils.ts +0 -17
  86. /package/dist/{components → lib/ui/uikit/dist/components}/PlElementList/PlElementList.vue.js.map +0 -0
  87. /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
- }