@milaboratories/uikit 2.2.23 → 2.2.25
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/CHANGELOG.md +13 -0
- package/dist/pl-uikit.js +2247 -2182
- package/dist/pl-uikit.umd.cjs +5 -5
- package/dist/src/components/PlEditableTitle/PlEditableTitle.vue.d.ts +1 -1
- package/dist/src/components/PlFileDialog/Remote.vue.d.ts +1 -1
- package/dist/src/components/PlFileDialog/Shortcuts.vue.d.ts +2 -0
- package/dist/src/components/PlTabs/Tab.vue.d.ts +11 -6
- package/dist/src/components/PlTooltip/PlTooltip.vue.d.ts +12 -3
- package/dist/src/components/PlTooltip/useTooltipPosition.d.ts +1 -1
- package/dist/style.css +1 -1
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/src/assets/base.scss +1 -1
- package/src/components/PlFileDialog/Remote.vue +22 -21
- package/src/components/PlFileDialog/Shortcuts.vue +102 -0
- package/src/components/PlTooltip/PlTooltip.vue +12 -3
- package/src/components/PlTooltip/pl-tooltip.scss +16 -2
- package/src/components/PlTooltip/useTooltipPosition.ts +6 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@milaboratories/uikit",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.25",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/pl-uikit.umd.js",
|
|
6
6
|
"module": "dist/pl-uikit.js",
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
"vue-tsc": "^2.1.10",
|
|
33
33
|
"yarpm": "^1.2.0",
|
|
34
34
|
"svgo": "^3.3.2",
|
|
35
|
-
"@
|
|
36
|
-
"@
|
|
35
|
+
"@milaboratories/helpers": "^1.6.8",
|
|
36
|
+
"@platforma-sdk/model": "^1.14.1"
|
|
37
37
|
},
|
|
38
38
|
"scripts": {
|
|
39
39
|
"dev": "vite",
|
package/src/assets/base.scss
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
2
|
+
import { useEventListener } from '@/composition/useEventListener';
|
|
3
|
+
import type { ImportedFiles } from '@/types';
|
|
4
4
|
import { between, notEmpty, tapIf } from '@milaboratories/helpers';
|
|
5
5
|
import type { StorageHandle } from '@platforma-sdk/model';
|
|
6
|
-
import
|
|
7
|
-
import { getFilePathBreadcrumbs, normalizeExtensions, type FileDialogItem } from './utils';
|
|
6
|
+
import { computed, onMounted, reactive, toRef, watch } from 'vue';
|
|
8
7
|
import { PlDropdown } from '../PlDropdown';
|
|
9
|
-
import { useEventListener } from '@/composition/useEventListener';
|
|
10
|
-
import { defaultData, useVisibleItems, vTextOverflown } from './remote';
|
|
11
|
-
import { PlSearchField } from '../PlSearchField';
|
|
12
8
|
import { PlIcon16 } from '../PlIcon16';
|
|
9
|
+
import Shortcuts from './Shortcuts.vue';
|
|
10
|
+
import { PlMaskIcon16 } from '../PlMaskIcon16';
|
|
11
|
+
import { PlSearchField } from '../PlSearchField';
|
|
12
|
+
import style from './pl-file-dialog.module.scss';
|
|
13
|
+
import { defaultData, useVisibleItems, vTextOverflown } from './remote';
|
|
14
|
+
import { getFilePathBreadcrumbs, normalizeExtensions, type FileDialogItem } from './utils';
|
|
13
15
|
|
|
14
16
|
// note that on a Mac, a click combined with the control key is intercepted by the operating system and used to open a context menu, so ctrlKey is not detectable on click events.
|
|
15
17
|
const isCtrlOrMeta = (ev: KeyboardEvent | MouseEvent) => ev.ctrlKey || ev.metaKey;
|
|
@@ -135,7 +137,7 @@ const selectFile = (ev: MouseEvent, file: FileDialogItem) => {
|
|
|
135
137
|
data.items.forEach((f) => (f.selected = false));
|
|
136
138
|
}
|
|
137
139
|
|
|
138
|
-
file.selected =
|
|
140
|
+
file.selected = !file.selected;
|
|
139
141
|
|
|
140
142
|
if (!props.multi) {
|
|
141
143
|
return;
|
|
@@ -189,22 +191,18 @@ const loadAvailableStorages = () => {
|
|
|
189
191
|
window.platforma.lsDriver
|
|
190
192
|
.getStorageList()
|
|
191
193
|
.then((storageEntries) => {
|
|
194
|
+
// local storage is always returned by the ML, so we need to remove it from remote dialog manually
|
|
195
|
+
storageEntries = storageEntries.filter((it) => it.name !== 'local' && !it.name.startsWith('local_disk_'));
|
|
196
|
+
|
|
192
197
|
data.storageOptions = storageEntries.map((it) => ({
|
|
193
198
|
text: it.name,
|
|
194
199
|
value: it,
|
|
195
200
|
}));
|
|
196
201
|
|
|
197
202
|
if (props.autoSelectStorage) {
|
|
198
|
-
tapIf(
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
e.name === 'local' || // the only local storage on unix systems
|
|
202
|
-
(e.name.startsWith('local_disk_') && e.initialFullPath.length > 4),
|
|
203
|
-
), // local drive where home folder is stored, normally C:\
|
|
204
|
-
(entry) => {
|
|
205
|
-
data.storageEntry = entry;
|
|
206
|
-
},
|
|
207
|
-
);
|
|
203
|
+
tapIf(storageEntries[0], (entry) => {
|
|
204
|
+
data.storageEntry = entry;
|
|
205
|
+
});
|
|
208
206
|
}
|
|
209
207
|
})
|
|
210
208
|
.catch((err) => (data.error = String(err)));
|
|
@@ -287,7 +285,10 @@ onMounted(loadAvailableStorages);
|
|
|
287
285
|
<PlIcon16 v-if="s.index !== breadcrumbs.length - 1" name="chevron-right" />
|
|
288
286
|
</template>
|
|
289
287
|
</div>
|
|
290
|
-
<div :class="style.selected">
|
|
288
|
+
<div :class="style.selected">
|
|
289
|
+
<span>Selected: {{ selectedFiles.length }}</span>
|
|
290
|
+
<Shortcuts />
|
|
291
|
+
</div>
|
|
291
292
|
</div>
|
|
292
293
|
<div v-if="data.currentLoadingPath !== undefined" class="ls-loader">
|
|
293
294
|
<i class="mask-24 mask-loading loader-icon" />
|
|
@@ -303,7 +304,7 @@ onMounted(loadAvailableStorages);
|
|
|
303
304
|
<div v-else :class="style['ls-body']">
|
|
304
305
|
<template v-for="file in visibleItems" :key="file.id">
|
|
305
306
|
<div v-if="file.isDir" :class="style.isDir" @click="setDirPath(file.path)">
|
|
306
|
-
<
|
|
307
|
+
<PlIcon16 name="chevron-right" />
|
|
307
308
|
<span v-text-overflown :title="file.name">{{ file.name }}</span>
|
|
308
309
|
</div>
|
|
309
310
|
<div
|
|
@@ -311,7 +312,7 @@ onMounted(loadAvailableStorages);
|
|
|
311
312
|
:class="{ [style.canBeSelected]: file.canBeSelected, [style.selected]: file.selected }"
|
|
312
313
|
@click.stop="(ev) => selectFile(ev, file)"
|
|
313
314
|
>
|
|
314
|
-
<
|
|
315
|
+
<PlMaskIcon16 name="box" :class="style.isFile" />
|
|
315
316
|
<span v-text-overflown :title="file.name">{{ file.name }}</span>
|
|
316
317
|
</div>
|
|
317
318
|
</template>
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { PlTooltip } from '../PlTooltip';
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<template>
|
|
6
|
+
<PlTooltip class="info" position="southwest" max-width="420px">
|
|
7
|
+
<template #tooltip>
|
|
8
|
+
<span :class="$style.title">Shortcuts</span>
|
|
9
|
+
|
|
10
|
+
<div :class="[$style.row, $style.head]">
|
|
11
|
+
<div></div>
|
|
12
|
+
<div>MacOS</div>
|
|
13
|
+
<div>Windows/Linux</div>
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
<div :class="[$style.row, $style.body]">
|
|
17
|
+
<div>Single File</div>
|
|
18
|
+
<div>Click the file</div>
|
|
19
|
+
<div>Click the file</div>
|
|
20
|
+
|
|
21
|
+
<div>Adjacent multiple files</div>
|
|
22
|
+
<div>Hold Shift, click first and last files</div>
|
|
23
|
+
<div>Hold Shift, click first and last files</div>
|
|
24
|
+
|
|
25
|
+
<div>Non-adjacent multiple files</div>
|
|
26
|
+
<div>Hold Command (⌘), click each file</div>
|
|
27
|
+
<div>Hold Ctrl, click each file</div>
|
|
28
|
+
|
|
29
|
+
<div>All files</div>
|
|
30
|
+
<div>Press Command (⌘) + A</div>
|
|
31
|
+
<div>Press Ctrl + A</div>
|
|
32
|
+
</div>
|
|
33
|
+
</template>
|
|
34
|
+
</PlTooltip>
|
|
35
|
+
</template>
|
|
36
|
+
|
|
37
|
+
<style lang="css" module>
|
|
38
|
+
.title {
|
|
39
|
+
display: inline-block;
|
|
40
|
+
font-size: 14px;
|
|
41
|
+
font-weight: 600;
|
|
42
|
+
line-height: 20px;
|
|
43
|
+
margin-bottom: 10px;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.row {
|
|
47
|
+
display: grid;
|
|
48
|
+
grid-template-columns: repeat(3, 1fr);
|
|
49
|
+
width: 100%;
|
|
50
|
+
color: #fff;
|
|
51
|
+
column-gap: 1px;
|
|
52
|
+
|
|
53
|
+
font-size: 14px;
|
|
54
|
+
font-weight: 500;
|
|
55
|
+
line-height: 20px;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.row > div:nth-child(3n + 1) {
|
|
59
|
+
padding-left: 4px;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.row > div:nth-child(3n) {
|
|
63
|
+
padding-right: 4px;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.head {
|
|
67
|
+
background-color: #110529;
|
|
68
|
+
position: relative;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.head:before {
|
|
72
|
+
position: absolute;
|
|
73
|
+
content: '';
|
|
74
|
+
background-color: #231842;
|
|
75
|
+
width: 12px;
|
|
76
|
+
left: -12px;
|
|
77
|
+
height: 100%;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.head:after {
|
|
81
|
+
position: absolute;
|
|
82
|
+
content: '';
|
|
83
|
+
background-color: #231842;
|
|
84
|
+
width: 12px;
|
|
85
|
+
right: -12px;
|
|
86
|
+
height: 100%;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.head > div {
|
|
90
|
+
padding: 6px 12px;
|
|
91
|
+
background-color: #231842;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.body {
|
|
95
|
+
background-color: #231842;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.body > div {
|
|
99
|
+
padding: 6px 12px;
|
|
100
|
+
background: #110529;
|
|
101
|
+
}
|
|
102
|
+
</style>
|
|
@@ -7,7 +7,7 @@ export default {
|
|
|
7
7
|
|
|
8
8
|
<script lang="ts" setup>
|
|
9
9
|
import './pl-tooltip.scss';
|
|
10
|
-
import { onUnmounted, reactive, ref, toRef, watch } from 'vue';
|
|
10
|
+
import { computed, onUnmounted, reactive, ref, toRef, watch } from 'vue';
|
|
11
11
|
import { useTooltipPosition } from './useTooltipPosition';
|
|
12
12
|
import * as utils from '@/helpers/utils';
|
|
13
13
|
import { useClickOutside } from '@/composition/useClickOutside';
|
|
@@ -31,7 +31,7 @@ const props = withDefaults(
|
|
|
31
31
|
/**
|
|
32
32
|
* Tooltip position
|
|
33
33
|
*/
|
|
34
|
-
position?: 'top-left' | 'left' | 'right' | 'top';
|
|
34
|
+
position?: 'top-left' | 'left' | 'right' | 'top' | 'southwest';
|
|
35
35
|
/**
|
|
36
36
|
* external prop to hide tooltips
|
|
37
37
|
*/
|
|
@@ -44,6 +44,10 @@ const props = withDefaults(
|
|
|
44
44
|
* base html element for tooltip
|
|
45
45
|
*/
|
|
46
46
|
element?: 'div' | 'span' | 'a' | 'p' | 'h1' | 'h2' | 'h3';
|
|
47
|
+
/**
|
|
48
|
+
* Max width (css value) of the tooltip container (default is 300px)
|
|
49
|
+
*/
|
|
50
|
+
maxWidth?: string;
|
|
47
51
|
}>(),
|
|
48
52
|
{
|
|
49
53
|
openDelay: 100,
|
|
@@ -51,6 +55,7 @@ const props = withDefaults(
|
|
|
51
55
|
gap: 8,
|
|
52
56
|
position: 'top',
|
|
53
57
|
element: 'div',
|
|
58
|
+
maxWidth: '300px',
|
|
54
59
|
},
|
|
55
60
|
);
|
|
56
61
|
|
|
@@ -135,6 +140,10 @@ const style = useTooltipPosition(rootRef, toRef(props));
|
|
|
135
140
|
|
|
136
141
|
useClickOutside([rootRef, tooltip], () => closeTooltip());
|
|
137
142
|
|
|
143
|
+
const tooltipStyle = computed(() => ({
|
|
144
|
+
'--pl-tooltip-max-width': props.maxWidth,
|
|
145
|
+
}));
|
|
146
|
+
|
|
138
147
|
onUnmounted(() => {
|
|
139
148
|
tMap.delete(tKey);
|
|
140
149
|
});
|
|
@@ -146,7 +155,7 @@ onUnmounted(() => {
|
|
|
146
155
|
<Teleport v-if="$slots['tooltip'] && data.open" to="body">
|
|
147
156
|
<Transition name="tooltip-transition">
|
|
148
157
|
<div v-if="data.tooltipOpen" class="pl-tooltip__container" :style="style">
|
|
149
|
-
<div ref="tooltip" class="pl-tooltip" :class="position" @mouseover="onOver" @mouseleave="onLeave">
|
|
158
|
+
<div ref="tooltip" class="pl-tooltip" :style="tooltipStyle" :class="position" @mouseover="onOver" @mouseleave="onLeave">
|
|
150
159
|
<!-- should be one line -->
|
|
151
160
|
<div><slot name="tooltip" /></div>
|
|
152
161
|
<Beak />
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
.pl-tooltip {
|
|
2
|
+
--pl-tooltip-max-width: 300px;
|
|
3
|
+
|
|
2
4
|
z-index: var(--z-tooltip);
|
|
3
5
|
position: absolute;
|
|
4
6
|
display: inline-block;
|
|
5
|
-
padding:
|
|
7
|
+
padding: 8px 12px 9px 12px;
|
|
6
8
|
background: var(--tooltip-bg);
|
|
7
9
|
border-radius: 6px;
|
|
8
10
|
width: max-content;
|
|
9
11
|
word-break: normal;
|
|
10
12
|
transform-origin: 0 50%;
|
|
11
|
-
max-width:
|
|
13
|
+
max-width: var(--pl-tooltip-max-width);
|
|
12
14
|
color: #fff;
|
|
13
15
|
|
|
14
16
|
&__container {
|
|
@@ -82,6 +84,18 @@
|
|
|
82
84
|
left: 50%;
|
|
83
85
|
}
|
|
84
86
|
}
|
|
87
|
+
|
|
88
|
+
&.southwest {
|
|
89
|
+
transform: translateY(100%);
|
|
90
|
+
bottom: 0;
|
|
91
|
+
right: -6px;
|
|
92
|
+
.beak {
|
|
93
|
+
position: absolute;
|
|
94
|
+
top: -2px;
|
|
95
|
+
transform: translateY(-50%) rotate(90deg);
|
|
96
|
+
right: 12px;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
85
99
|
}
|
|
86
100
|
|
|
87
101
|
.tooltip-transition {
|
|
@@ -3,7 +3,7 @@ import { useElementPosition } from '@/composition/usePosition';
|
|
|
3
3
|
import type { ElementPosition } from '@/types';
|
|
4
4
|
|
|
5
5
|
type Options = {
|
|
6
|
-
position: 'top-left' | 'right' | 'left' | 'top';
|
|
6
|
+
position: 'top-left' | 'right' | 'left' | 'top' | 'southwest';
|
|
7
7
|
gap: number;
|
|
8
8
|
};
|
|
9
9
|
|
|
@@ -33,6 +33,7 @@ export function useTooltipPosition(el: Ref<HTMLElement | undefined>, optionsRef:
|
|
|
33
33
|
|
|
34
34
|
const offsetMiddleY = pos.offsetY + Math.floor(pos.height / 2);
|
|
35
35
|
const offsetMiddleX = pos.offsetX + Math.floor(pos.width / 2);
|
|
36
|
+
|
|
36
37
|
if (position === 'top-left') {
|
|
37
38
|
return `left: ${pos.offsetX}px; top: ${pos.offsetY - gap}px;`;
|
|
38
39
|
}
|
|
@@ -49,6 +50,10 @@ export function useTooltipPosition(el: Ref<HTMLElement | undefined>, optionsRef:
|
|
|
49
50
|
return `right: ${pos.scrollWidth - pos.x + gap}px; top: ${offsetMiddleY}px;`;
|
|
50
51
|
}
|
|
51
52
|
|
|
53
|
+
if (position === 'southwest') {
|
|
54
|
+
return `left: ${pos.offsetX + pos.width}px; top: ${pos.offsetY + pos.height + gap}px;`;
|
|
55
|
+
}
|
|
56
|
+
|
|
52
57
|
return '';
|
|
53
58
|
});
|
|
54
59
|
}
|