@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@milaboratories/uikit",
3
- "version": "2.2.23",
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
- "@platforma-sdk/model": "^1.14.1",
36
- "@milaboratories/helpers": "^1.6.8"
35
+ "@milaboratories/helpers": "^1.6.8",
36
+ "@platforma-sdk/model": "^1.14.1"
37
37
  },
38
38
  "scripts": {
39
39
  "dev": "vite",
@@ -61,7 +61,7 @@
61
61
  --chip-close-ic-hover-color: #110529;
62
62
 
63
63
  --tooltip-link-color: hsla(160, 100%, 37%, 1);
64
- --tooltip-bg: #24223d;
64
+ --tooltip-bg: var(--bg-base-dark, #110529);
65
65
 
66
66
  --theme-switcher-icon-color: var(--txt-01);
67
67
 
@@ -1,15 +1,17 @@
1
1
  <script lang="ts" setup>
2
- import style from './pl-file-dialog.module.scss';
3
- import { watch, reactive, computed, toRef, onMounted } from 'vue';
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 type { ImportedFiles } from '@/types';
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 = true;
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
- storageEntries.find(
200
- (e) =>
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">Selected: {{ selectedFiles.length }}</div>
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
- <i class="icon-16 icon-chevron-right" />
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
- <i class="mask-16 mask-box" :class="style.isFile" />
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: 7px 12px 9px 12px;
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: 300px;
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
  }